We have a multi-threaded program that has one thread sitting in a while loop blocking from
recvfrom system call on a socket. I need to run this C program on mobile. Unfortunately, in the networking side of mobile development, IP address changes all the time and the socket descriptor becomes invalid. Hence we need to break the loop and reconnect the socket.
First approach is to destroy the thread the recreate it again when IP address is changed. So the thread can go through closing the old socket gracefully, creates a new socket with the new IP address and enters the while loop of receiving packets. Quick and simple. However, if you are porting a multi-threaded C/C++ program for Android, perhaps this may not be a smooth ride. This is because
pthread_cancel is not available in the Android NDK. So we can’t kill the thread and we need a way to signal blocking I/O
Second approach is to
close the socket descriptor and the
recvfrom should return with error. However, this doesn’t happen in Android. The
recvfrom continues to block.
Third approach is to set non-blocking I/O option in socket and handles the
errno returning from
struct time tv; tv.tv_sec = 1; setsockopt(socketfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
Another surprise in Android, it won’t let you do that.
I am running out of magic 8-ball. Luckily, the shutdown system call on socket lets you terminate the blocking I/O.
At the time of writing, I’m using API level 24.
If you plan to use semaphores on Android, then don’t. This is because the sem_open, sem_close and sem_unlink are not implemented. If you call sem_open on Android, you will get EACCESS error regardlessly.
This is what is defined in the /usr/include/semaphore.h in NDK’s sysroot directory.
int sem_destroy(sem_t*); int sem_getvalue(sem_t*, int*); int sem_init(sem_t*, int, unsigned int); int sem_post(sem_t*); int sem_timedwait(sem_t*, const struct timespec*); int sem_trywait(sem_t*); int sem_wait(sem_t*); /* These aren't actually implemented. */ sem_t* sem_open(const char*, int, ...); int sem_close(sem_t*); int sem_unlink(const char*); __END_DECLS #endif /* _SEMAPHORE_H */
The only workaround is to use mutex and conditional variable. Fortunately, there are many online helps on how to do it. Here is an example.