This is the mail archive of the libc-help@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: losing events with EPOLLONESHOT and cancellation


Carlos O'Donell <carlos@systemhalted.org> wrote:
> On Tue, Jun 11, 2013 at 8:38 PM, Eric Wong <normalperson@yhbt.net> wrote:
> > I seem to be encountering lost events with epoll_wait/epoll_pwait when
> > using EPOLLONESHOT and pthreads cancellation.
> 
> You are correct.
> 
> POSIX has this to say about the cancellation and the waiting event:
> ~~~
> ... if the thread is suspended at a cancellation point and the
> event for which it is waiting occurs before the cancellation request
> is acted upon, it is unspecified whether the cancellation request is
> acted upon or whether the cancellation request remains pending
> and the thread resumes normal execution. ...
> ~~~
> Therefore you must accept that it could be possible to get the data
> and then be cancelled.
> 
> The only recourse that I am aware of is to use a cancellation cleanup
> handler to attempt to restore the lost data.
> 
> See pthread_cleanup_push and pthread_cleanup_pop:
> http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cleanup_push.html
> 
> Does that answer your question?

Thanks.  With pthread_cleanup_*, I can't see the return value of the
cancelled syscall.  So I think my alternative is to not rely on normal
syscalls being cancellable and explicitly put cancellation points in my
program around interruptible syscalls, using pthread_kill in a loop in
addition to pthread_cancel.

Something like this:

thread_1
--------
pthread_cancel(thread_2);

/*
 * trigger EINTR in any interruptible syscall
 * the loop seems icky, but this will be a rare code path
 */
while (pthread_kill(thread_2, ...) == 0)
	sched_yield();

thread_2
--------

pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

for (;;) {
	/* open a brief window for async cancellation */
	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

	/*
	 * We could lose cancellation requests here, so we loop in thread_1.
	 * I also have a similar loop doing blocking accept4 in a
	 * different thread.
	 */
	rc = epoll_wait(...);

	if (rc < 0 && errno == EINTR) {
		/* open a brief window for async cancellation */
		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
	}
	...
}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]