----------
Known bugs
----------

1. Not strictly a bug, more of a gotcha.

   Under MS VC++ (only tested with version 6.0), a term_func
   set via the standard C++ set_terminate() function causes the
   application to abort.

   Notes from the MSVC++ manual:
         1) A term_func() should call exit(), otherwise
            abort() will be called on return to the caller.
            A call to abort() raises SIGABRT and the default signal handler
            for all signals terminates the calling program with
            exit code 3.
         2) A term_func() must not throw an exception. Therefore
            term_func() should not call pthread_exit(), which
            works by throwing an exception (pthreadVCE or pthreadVSE)
            or by calling longjmp (pthreadVC).

   Workaround: avoid using pthread_exit() in C++ applications. Exit
   threads by dropping through the end of the thread routine.

2. Cancellation problems in optimised code
   - Milan Gardian

   Workaround [rpj - 2 Feb 2002]
   -----------------------------
   The problem disappears when /Ob0 is used, i.e. /O2 /Ob0 works OK,
   but if you want to use inlining optimisation you can be much more
   specific about where it's switched off and on by using a pragma.

   So the inlining optimisation is interfering with the way that cleanup
   handlers are run. It appears to relate to auto-inlining of class methods
   since this is the only auto inlining that is performed at /O1 optimisation
   (functions with the "inline" qualifier are also inlined, but the problem
   doesn't appear to involve any such functions in the library or testsuite).

   In order to confirm the inlining culprit, the following use of pragmas
   eliminate the problem but I don't know how to make it transparent, putting
   it in, say, pthread.h where pthread_cleanup_push defined as a macro.

   #pragma inline_depth(0)
     pthread_cleanup_push(handlerFunc, (void *) &arg);

        /* ... */

     pthread_cleanup_pop(0);
   #pragma inline_depth()

   Note the empty () pragma value after the pop macro. This resets depth to the
   default. Or you can specify a non-zero depth here.

   The pragma is also needed (and now used) within the library itself wherever
   cleanup handlers are used (condvar.c and rwlock.c).

   Use of these pragmas allows compiler optimisations /O1 and /O2 to be
   used for either or both the library and applications.

   Experimenting further, I found that wrapping the actual cleanup handler
   function with #pragma auto_inline(off|on) does NOT work.

   MSVC6.0 doesn't appear to support the C99 standard's _Pragma directive,
   however, later versions may. This form is embeddable inside #define
   macros, which would be ideal because it would mean that it could be added
   to the push/pop macro definitions in pthread.h and hidden from the
   application programmer.

   [/rpj]

   Original problem description
   ----------------------------

   The cancellation (actually, cleanup-after-cancel) tests fail when using VC
   (professional) optimisation switches (/O1 or /O2) in pthreads library. I
   have not investigated which concrete optimisation technique causes this
   problem (/Og, /Oi, /Ot, /Oy, /Ob1, /Gs, /Gf, /Gy, etc.), but here is a
   summary of builds and corresponding failures:

     * pthreads VSE (optimised tests): OK
     * pthreads VCE (optimised tests): Failed "cleanup1" test (runtime)

     * pthreads VSE (DLL in CRT, optimised tests): OK
     * pthreads VCE (DLL in CRT, optimised tests): Failed "cleanup1" test
   (runtime)

   Please note that while in VSE version of the pthreads library the
   optimisation does not really have any impact on the tests (they pass OK), in
   VCE version addition of optimisation (/O2 in this case) causes the tests to
   fail uniformly - either in "cleanup0" or "cleanup1" test cases.

   Please note that all the tests above use default pthreads DLL (no
   optimisations, linked with either static or DLL CRT, based on test type).
   Therefore the problem lies not within the pthreads DLL but within the
   compiled client code (the application using pthreads -> involvement of
   "pthread.h").

   I think the message of this section is that usage of VCE version of pthreads
   in applications relying on cancellation/cleanup AND using optimisations for
   creation of production code is highly unreliable for the current version of
   the pthreads library.


3. sem_getvalue sometimes returns lower value than expected

   The following comments from the code explain the problem:

      /*
       * There appears to be NO atomic means of determining the
       * value of the semaphore. Using only ReleaseSemaphore()
       * with either a zero or oversized count parameter has been
       * suggested but this trick doesn't produce consistent results
       * across Windows versions (the technique uses values that are
       * knowingly illegal but hopes to extract the current value
       * anyway - the zero parameter appears to work for Win9x but
       * neither work reliably for WinNT).
       *
       * The intrusive method below will give false results
       * at times but it at least errs on the side of
       * caution. Competing threads might occasionally believe
       * the semaphore has a count of one less than it actually
       * would have and possibly block momentarily unecessarily,
       * but they will never see a higher semaphore value than
       * there should be.
       *
       *
       * Multiple threads calling sem_getvalue() at the same time
       * may not all return the same value (assuming no calls to
       * other semaphore routines). They will always return the
       * correct value or a lesser value. This problem could be fixed
       * with a global or a per-semaphore critical section here.
       *
       * An equally approximate but IMO slightly riskier approach
       * would be to keep a separate per-semaphore counter and
       * decrement/increment it inside of sem_wait() and sem_post()
       * etc using the Interlocked* functions.
       */