Robert N. M. Watson wrote:
This is an interesting idea. My first thought was to look at whether pthreads + libevent would provide a reasonable foundation for a libnqkqueue ("not quite kqueue") wrapper library implementing (roughly) the kqueue interface on non-supporting systems. There are some problems with this idea, not least that libevent can't provided a unified event source for some of the types of events supported by kqueue. On the other hand, it would offer significantly more portability (at the cost of less efficiency and fewer capabilities).
APR and libevent aren't mutually exclusive. You could use APR to emulate pthreads on Windows, and libevent to emulate kqueue(2) on non-BSD systems. You might also want to look at a library I wrote called pnotify. This provides a wrapper around BSD's kqueue and Linux's inotify to monitor filesystem events. The website is here: http://mark.heily.com/pnotify/ If portability to non-POSIX platforms is a goal, libevent doesn't provide any emulation of pthreads, so you would need something like APR. Regards, - Mark P.S. Here are my notes from examining libevent and APR and thinking about the requirements of libdispatch. Hope this is helpful. Requirements for portability --- In order to support non-POSIX operating systems like MS Windows, libdispatch needs to utilize the following operating system primitives in a portable way: 1. threads 2. mutexes 3. time functions; e.g. gettimeofday(2) 4. semaphores 5. threadsafe atomic operations 6. thread pools Suitability of APR --- APR is very well suited to writing portable applications. 1. threads Supported. See: apr_thread_create() 2. mutexes Supported. See: apr_thread_mutex_create() apr_thread_mutex_lock() apr_thread_mutex_unlock() 3. time functions; e.g. gettimeofday(2) Supported. See: apr_time_now() 4. semaphores Not supported directly; however, condition variables are supported which may work. Semaphores are also trivial to implement as follows[1]: sem_wait(...) { if (apr_atomic_dec32 (&count) < 0) apr_thread_mutex_lock (mutex); } sem_post(...) { if ((apr_int32_t) apr_atomic_inc32 (&count) <= 0) apr_thread_mutex_unlock (mutex); } [1] Credit to http://markmail.org/message/qqp7nni2gyltvyrd 5. threadsafe atomic operations APR provides a wide range of atomic aperations. See: apr_atomic_inc32 apr_atomic_dec32 apr_atomic_cas32 6. thread pools APR 1.3 provides a very sophisticated thread pool implementation. See: apr_thread_pool_create() apr_thread_pool_push() Suitability of libevent --- libevent does not provide any abstractions for operating system primitives. ======================================================================= Requirements for dispatch sources --- libdispatch needs to support the following dispatch sources: 1. socket readiness 2. signals 3. filesystem changes 4. timers 5. subprocess changes (fork, exit, etc.) 6. user-defined event sources Suitability of APR --- 1. socket readiness APR provides a generic polling mechanism that uses kqueue, epoll, poll, select, or WSApoll. See: apr_pollset_add() apr_pollset_remove() apr_pollset_poll() 2. signals APR allows you to setup a dedicated thread to perform signal handling. This is generally better than using signal handlers, because it avoids the need to add EINTR checks after every system call. See: apr_setup_signal_thread(); apr_signal_thread(); 3. timers Not supported. One solution would be to have a dedicated timekeeper thread that wakes up at regular intervals and generates timer events. 4. filesystem changes Not supported. One solution would be to have a dedicated filesystem event thread that uses platform-specific facilities for monitoring filesystem events. 5. subprocess changes (fork, exit, etc.) Not supported. I'm not sure how this event source is useful. 6. user-defined event sources This could be implemented in separate threads. Suitability of libevent --- 1. socket readiness libevent can uses kqueue, epoll, poll, select, or WSApoll. See: event_set() event_add() 2. signals signal handling is performed using a signal handler that writes to a pipe that is monitored by poll(2) or the platform-specific alternative. See: signal_set() signal_add() 3. timers Timers are supported. See: evtimer_set() evtimer_add() 4. filesystem changes Not supported. One solution would be to have a dedicated filesystem event thread that uses platform-specific facilities for monitoring filesystem events. A socketpair(2) would be needed to notify the event_dispatch() loop of new events. 5. subprocess changes (fork, exit, etc.) Not supported. I'm not sure how this event source is useful. 6. user-defined event sources This could be implemented in separate threads. A socketpair(2) would be needed to notify the event_dispatch() loop of new events.