Search code examples
cmultithreadingpthreadsposixcancellation

pthread_cancel returning EINPROGRESS


I am maintaining some code right now, that creates a pthread with pthread_create(). This thread also calls pthread_detach(pthread_self()); soon after creation. Furthermore it uses pthread_cleanup_push() to push a clean-up handler. The only cancellation point of this thread is a call to pthread_testcancel() at the end of the threads main loop.

I now see, that at some point pthread_cancel() gets called on this thread and (almost) always returns a nonzero value. Checking errno results in EINPROGRESS. What exactly does this mean? Because the man pages states

On success, pthread_cancel() returns 0

However, it also mentions,

that cancellation will be delayed until the thread next calls a function that is a cancellation point.

So if a return value of nonzero and errno equal to EINPROGRESS means, that the cancellation request got queued, but was not yet reacted upon, I would expect that to be always the case. But if a return value of 0 indicates success, then it must mean something different.

What does EINPROGRESS mean in this circumstance and how can I make sure, that the thread got canceled correctly or was already terminated?


I am running Debian 7.4 with libpthread-2.13 as part of libc6:amd64 2.13-38+deb7u1 in a VM.


Solution

  • I now see, that at some point pthread_cancel() gets called on this thread and (almost) always returns a nonzero value. Checking errno results in EINPROGRESS.

    The pthread* family of functions does not set errno, but instead returns the error code as function value.

    So do not only test the outcome of the call to pthread_cancel() against 0, but actually interpret the value returned as what you "normaly" find in errno, that is one of the E* error values.

    int result = pthread_cancel(<some-pthread>);
    if (0 != result)
    {
      fprintf(stderr, "pthread_cancel() failed with error #%d: '%s'\n", result, strerror(result)); /* Better use strerror_r() in a multithreaded enviroment. */
    }
    

    Btw: Inspecting the sources of the libc you seem to be using does not reveal any hints of pthread_cancel() returning EINPROGRESS.