[BACK]Return to pthread_barrier.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libpthread

Annotation of src/lib/libpthread/pthread_barrier.c, Revision 1.18

1.18    ! ad          1: /*     $NetBSD: pthread_barrier.c,v 1.17 2008/04/28 20:23:01 martin Exp $      */
1.2       thorpej     2:
                      3: /*-
1.10      ad          4:  * Copyright (c) 2001, 2003, 2006, 2007 The NetBSD Foundation, Inc.
1.2       thorpej     5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
1.11      ad          8:  * by Nathan J. Williams, by Jason R. Thorpe, and by Andrew Doran.
1.2       thorpej     9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     20:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     21:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     22:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     23:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     24:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     25:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     26:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     27:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     28:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     29:  * POSSIBILITY OF SUCH DAMAGE.
                     30:  */
1.6       lukem      31:
                     32: #include <sys/cdefs.h>
1.18    ! ad         33: __RCSID("$NetBSD: pthread_barrier.c,v 1.17 2008/04/28 20:23:01 martin Exp $");
1.2       thorpej    34:
                     35: #include <errno.h>
                     36:
                     37: #include "pthread.h"
                     38: #include "pthread_int.h"
                     39:
                     40: int
                     41: pthread_barrier_init(pthread_barrier_t *barrier,
1.18    ! ad         42:                     const pthread_barrierattr_t *attr, unsigned int count)
1.2       thorpej    43: {
1.18    ! ad         44:        pthread_mutex_t *interlock;
        !            45:
1.2       thorpej    46: #ifdef ERRORCHECK
                     47:        if ((barrier == NULL) ||
                     48:            (attr && (attr->ptba_magic != _PT_BARRIERATTR_MAGIC)))
                     49:                return EINVAL;
                     50: #endif
                     51:
                     52:        if (count == 0)
                     53:                return EINVAL;
                     54:
                     55:        if (barrier->ptb_magic == _PT_BARRIER_MAGIC) {
1.18    ! ad         56:                interlock = pthread__hashlock(barrier);
1.15      ad         57:
1.2       thorpej    58:                /*
                     59:                 * We're simply reinitializing the barrier to a
                     60:                 * new count.
                     61:                 */
1.18    ! ad         62:                pthread_mutex_lock(interlock);
1.2       thorpej    63:
                     64:                if (barrier->ptb_magic != _PT_BARRIER_MAGIC) {
1.18    ! ad         65:                        pthread_mutex_unlock(interlock);
1.2       thorpej    66:                        return EINVAL;
                     67:                }
                     68:
                     69:                if (!PTQ_EMPTY(&barrier->ptb_waiters)) {
1.18    ! ad         70:                        pthread_mutex_unlock(interlock);
1.2       thorpej    71:                        return EBUSY;
                     72:                }
                     73:
                     74:                barrier->ptb_initcount = count;
                     75:                barrier->ptb_curcount = 0;
1.3       nathanw    76:                barrier->ptb_generation = 0;
1.2       thorpej    77:
1.18    ! ad         78:                pthread_mutex_unlock(interlock);
1.2       thorpej    79:
                     80:                return 0;
                     81:        }
                     82:
                     83:        barrier->ptb_magic = _PT_BARRIER_MAGIC;
                     84:        PTQ_INIT(&barrier->ptb_waiters);
                     85:        barrier->ptb_initcount = count;
                     86:        barrier->ptb_curcount = 0;
1.3       nathanw    87:        barrier->ptb_generation = 0;
1.2       thorpej    88:
                     89:        return 0;
                     90: }
                     91:
                     92:
                     93: int
                     94: pthread_barrier_destroy(pthread_barrier_t *barrier)
                     95: {
1.18    ! ad         96:        pthread_mutex_t *interlock;
1.2       thorpej    97:
                     98: #ifdef ERRORCHECK
                     99:        if ((barrier == NULL) || (barrier->ptb_magic != _PT_BARRIER_MAGIC))
                    100:                return EINVAL;
                    101: #endif
                    102:
1.18    ! ad        103:        interlock = pthread__hashlock(barrier);
        !           104:        pthread_mutex_lock(interlock);
1.2       thorpej   105:
                    106:        if (barrier->ptb_magic != _PT_BARRIER_MAGIC) {
1.18    ! ad        107:                pthread_mutex_unlock(interlock);
1.2       thorpej   108:                return EINVAL;
                    109:        }
                    110:
                    111:        if (!PTQ_EMPTY(&barrier->ptb_waiters)) {
1.18    ! ad        112:                pthread_mutex_unlock(interlock);
1.2       thorpej   113:                return EBUSY;
                    114:        }
                    115:
                    116:        barrier->ptb_magic = _PT_BARRIER_DEAD;
                    117:
1.18    ! ad        118:        pthread_mutex_unlock(interlock);
1.2       thorpej   119:
                    120:        return 0;
                    121: }
                    122:
                    123:
                    124: int
                    125: pthread_barrier_wait(pthread_barrier_t *barrier)
                    126: {
1.18    ! ad        127:        pthread_mutex_t *interlock;
1.2       thorpej   128:        pthread_t self;
1.3       nathanw   129:        unsigned int gen;
1.2       thorpej   130:
                    131: #ifdef ERRORCHECK
                    132:        if ((barrier == NULL) || (barrier->ptb_magic != _PT_BARRIER_MAGIC))
                    133:                return EINVAL;
                    134: #endif
                    135:        self = pthread__self();
1.18    ! ad        136:        interlock = pthread__hashlock(barrier);
1.2       thorpej   137:
1.18    ! ad        138:        pthread_mutex_lock(interlock);
1.2       thorpej   139:
                    140:        /*
                    141:         * A single arbitrary thread is supposed to return
                    142:         * PTHREAD_BARRIER_SERIAL_THREAD, and everone else
                    143:         * is supposed to return 0.  Since pthread_barrier_wait()
                    144:         * is not a cancellation point, this is trivial; we
                    145:         * simply elect that the thread that causes the barrier
                    146:         * to be satisfied gets the special return value.  Note
                    147:         * that this final thread does not actually need to block,
                    148:         * but instead is responsible for waking everyone else up.
                    149:         */
                    150:        if (barrier->ptb_curcount + 1 == barrier->ptb_initcount) {
1.8       ad        151:                barrier->ptb_generation++;
1.18    ! ad        152:                pthread__unpark_all(&barrier->ptb_waiters, self,
        !           153:                    interlock);
        !           154:                pthread_mutex_unlock(interlock);
1.2       thorpej   155:                return PTHREAD_BARRIER_SERIAL_THREAD;
                    156:        }
                    157:
1.3       nathanw   158:        barrier->ptb_curcount++;
                    159:        gen = barrier->ptb_generation;
                    160:        while (gen == barrier->ptb_generation) {
1.11      ad        161:                PTQ_INSERT_TAIL(&barrier->ptb_waiters, self, pt_sleep);
                    162:                self->pt_sleepobj = &barrier->ptb_waiters;
1.18    ! ad        163:                (void)pthread__park(self, interlock, &barrier->ptb_waiters,
        !           164:                    NULL, 0, __UNVOLATILE(&interlock->ptm_waiters));
        !           165:                pthread_mutex_lock(interlock);
1.3       nathanw   166:        }
1.18    ! ad        167:        pthread_mutex_unlock(interlock);
1.2       thorpej   168:
                    169:        return 0;
                    170: }
                    171:
                    172:
                    173: int
                    174: pthread_barrierattr_init(pthread_barrierattr_t *attr)
                    175: {
                    176:
                    177: #ifdef ERRORCHECK
                    178:        if (attr == NULL)
                    179:                return EINVAL;
                    180: #endif
                    181:
                    182:        attr->ptba_magic = _PT_BARRIERATTR_MAGIC;
                    183:
                    184:        return 0;
                    185: }
                    186:
                    187:
                    188: int
                    189: pthread_barrierattr_destroy(pthread_barrierattr_t *attr)
                    190: {
                    191:
                    192: #ifdef ERRORCHECK
                    193:        if ((attr == NULL) ||
                    194:            (attr->ptba_magic != _PT_BARRIERATTR_MAGIC))
                    195:                return EINVAL;
                    196: #endif
                    197:
                    198:        attr->ptba_magic = _PT_BARRIERATTR_DEAD;
                    199:
                    200:        return 0;
                    201: }

CVSweb <webmaster@jp.NetBSD.org>