Hi,
I was expecting apr_pollset_poll to return from blocking if the socket
was closed, but this does not seems to be the case on OpenSolaris(Neveda
build 35).
Haven't get a chance to test on other platform, but wondering if this is
reasonable to expect. If it is, what do I miss in the testing code?
Attached please find the test program reveals the problem, basically
what it does is to listen on a socket, and start a thread to poll on
that socket. Wait a while to close the socket and join on the polling
thread.
Any ideas are welcome, thank you in advance. :-)
Cheers,
Henry
#include <apr_poll.h>
#include <apr_thread_proc.h>
#include <apr_network_io.h>
static int running = 0;
static void* APR_THREAD_FUNC do_poll(apr_thread_t * thd, void * arg)
{
apr_pollset_t * pollset = arg;
apr_status_t rv;
apr_int32_t num;
const apr_pollfd_t * fds;
apr_int32_t ev;
while (running) {
printf("Waiting apr_pollset_poll ...\n");
rv = apr_pollset_poll(pollset, -1L, &num, &fds);
if (APR_SUCCESS != rv) {
printf("apr_pollset_poll failed with status %d\n", rv);
return NULL;
}
printf("Came back from apr_pollset_poll.\n");
while (num > 0) {
num --;
ev = fds->rtnevents;
printf("APR_POLLIN %d APR_POLLPRI %d APR_POLLERR %d "
"APR_POLLHUP %d APR_POLLNVAL %d\n", ev & APR_POLLIN ? 1:0,
ev & APR_POLLPRI ? 1:0, ev & APR_POLLERR ? 1:0,
ev & APR_POLLHUP ? 1:0, ev & APR_POLLNVAL ? 1:0);
fds++;
}
}
return NULL;
}
apr_status_t
socket_listen(apr_socket_t ** me, const char * addr, apr_port_t port,
apr_int32_t backlog, apr_pool_t * p)
{
apr_status_t rv;
apr_sockaddr_t * sa;
char msg[256];
rv = apr_sockaddr_info_get(&sa, addr, APR_UNSPEC, port, 0, p);
if (APR_SUCCESS != rv) {
apr_strerror(rv, msg, sizeof(msg));
printf("Socket addr info failed : %s\n", msg);
*me = NULL;
return rv;
}
rv = apr_socket_create(me, sa->family, SOCK_STREAM, APR_PROTO_TCP, p);
if (APR_SUCCESS != rv) {
apr_strerror(rv, msg, sizeof(msg));
printf("Failed create server socket : %s\n", msg);
*me = NULL;
return rv;
}
/* REUSEADDR: this may help in case of the port is in TIME_WAIT */
/*
rv = apr_socket_opt_set(*me, APR_SO_REUSEADDR, 1);
if (APR_SUCCESS != rv) {
apr_strerror(rv, msg, sizeof(msg));
printf("Failed setting options : %s\n", msg);
}
*/
/* bind */
rv = apr_socket_bind(*me, sa);
if (APR_SUCCESS != rv) {
apr_socket_close(*me);
apr_strerror(rv, msg, sizeof(msg));
printf("Failed to bind socket : %s\n", msg);
*me = NULL;
return rv;
}
/* listen */
rv = apr_socket_listen(*me, backlog);
if (APR_SUCCESS != rv) {
apr_socket_close(*me);
apr_strerror(rv, msg, sizeof(msg));
printf("Failed to listen on socket : %s\n", msg);
*me = NULL;
return rv;
}
return APR_SUCCESS;
}
int main(int argc, char **argv)
{
apr_pool_t *p;
apr_pollset_t *pollset;
apr_status_t rv;
apr_socket_t *s;
apr_pollfd_t fd;
apr_thread_t *thd;
apr_initialize();
rv = apr_pool_create(&p, NULL);
rv = apr_pollset_create(&pollset, 10, p, APR_POLLSET_THREADSAFE);
if (APR_SUCCESS != rv) {
return rv;
}
rv = socket_listen(&s, "127.0.0.1", 9701, 10, p);
if (APR_SUCCESS != rv) {
return rv;
}
fd.p = p;
fd.desc_type = APR_POLL_SOCKET;
fd.desc.s = s;
fd.reqevents = APR_POLLIN | APR_POLLPRI | APR_POLLERR | APR_POLLHUP |
APR_POLLNVAL;
rv = apr_pollset_add(pollset, &fd);
if (APR_SUCCESS != rv) {
printf("Failed to add pollset\n");
return rv;
}
running = 1;
rv = apr_thread_create(&thd, NULL, do_poll, pollset, p);
if (APR_SUCCESS != rv) {
printf("Failed to create thread\n");
return rv;
}
printf("Wait for 60 seconds ...\n");
apr_sleep(60L * 1000000L);
printf("Closing socket ...\n");
running = 0;
apr_socket_shutdown(s, APR_SHUTDOWN_READWRITE);
apr_socket_close(s);
printf("Waiting polling thread to stop ...\n");
apr_thread_join(&rv, thd);
apr_pool_destroy(p);
apr_terminate();
return 0;
}
/* vim: set et sw=4 ts=4 tw=80: */