Home | History | Annotate | Download | only in pthreads-win32
      1 /*
      2  * pthread_barrier_wait.c
      3  *
      4  * Description:
      5  * This translation unit implements barrier primitives.
      6  *
      7  * --------------------------------------------------------------------------
      8  *
      9  *      Pthreads-win32 - POSIX Threads Library for Win32
     10  *      Copyright(C) 1998 John E. Bossom
     11  *      Copyright(C) 1999,2005 Pthreads-win32 contributors
     12  *
     13  *      Contact Email: rpj (at) callisto.canberra.edu.au
     14  *
     15  *      The current list of contributors is contained
     16  *      in the file CONTRIBUTORS included with the source
     17  *      code distribution. The list can also be seen at the
     18  *      following World Wide Web location:
     19  *      http://sources.redhat.com/pthreads-win32/contributors.html
     20  *
     21  *      This library is free software; you can redistribute it and/or
     22  *      modify it under the terms of the GNU Lesser General Public
     23  *      License as published by the Free Software Foundation; either
     24  *      version 2 of the License, or (at your option) any later version.
     25  *
     26  *      This library is distributed in the hope that it will be useful,
     27  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
     28  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     29  *      Lesser General Public License for more details.
     30  *
     31  *      You should have received a copy of the GNU Lesser General Public
     32  *      License along with this library in the file COPYING.LIB;
     33  *      if not, write to the Free Software Foundation, Inc.,
     34  *      59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
     35  */
     36 
     37 #include "pthread.h"
     38 #include "implement.h"
     39 
     40 
     41 int
     42 pthread_barrier_wait (pthread_barrier_t * barrier)
     43 {
     44   int result;
     45   pthread_barrier_t b;
     46 
     47   ptw32_mcs_local_node_t node;
     48 
     49   if (barrier == NULL || *barrier == (pthread_barrier_t) PTW32_OBJECT_INVALID)
     50     {
     51       return EINVAL;
     52     }
     53 
     54   ptw32_mcs_lock_acquire(&(*barrier)->lock, &node);
     55 
     56   b = *barrier;
     57   if (--b->nCurrentBarrierHeight == 0)
     58     {
     59       /*
     60        * We are the last thread to arrive at the barrier before it releases us.
     61        * Move our MCS local node to the global scope barrier handle so that the
     62        * last thread out (not necessarily us) can release the lock.
     63        */
     64       ptw32_mcs_node_transfer(&b->proxynode, &node);
     65 
     66       /*
     67        * Any threads that have not quite entered sem_wait below when the
     68        * multiple_post has completed will nevertheless continue through
     69        * the semaphore (barrier).
     70        */
     71       result = (b->nInitialBarrierHeight > 1
     72                 ? sem_post_multiple (&(b->semBarrierBreeched),
     73 				     b->nInitialBarrierHeight - 1) : 0);
     74     }
     75   else
     76     {
     77       ptw32_mcs_lock_release(&node);
     78       /*
     79        * Use the non-cancelable version of sem_wait().
     80        *
     81        * It is possible that all nInitialBarrierHeight-1 threads are
     82        * at this point when the last thread enters the barrier, resets
     83        * nCurrentBarrierHeight = nInitialBarrierHeight and leaves.
     84        * If pthread_barrier_destroy is called at that moment then the
     85        * barrier will be destroyed along with the semas.
     86        */
     87       result = ptw32_semwait (&(b->semBarrierBreeched));
     88     }
     89 
     90   if ((PTW32_INTERLOCKED_LONG)PTW32_INTERLOCKED_INCREMENT_LONG((PTW32_INTERLOCKED_LONGPTR)&b->nCurrentBarrierHeight)
     91 		  == (PTW32_INTERLOCKED_LONG)b->nInitialBarrierHeight)
     92     {
     93       /*
     94        * We are the last thread to cross this barrier
     95        */
     96       ptw32_mcs_lock_release(&b->proxynode);
     97       if (0 == result)
     98         {
     99           result = PTHREAD_BARRIER_SERIAL_THREAD;
    100         }
    101     }
    102 
    103   return (result);
    104 }
    105