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: */

Reply via email to