Ticket #5694: 0001-Implemented-pthread-barriers.patch

File 0001-Implemented-pthread-barriers.patch, 9.5 KB (added by hermord, 7 years ago)

My implementation of pthread barriers

  • headers/posix/pthread.h

    From 889211b941cee0c62ec7e11588d71527906fd35a Mon Sep 17 00:00:00 2001
    From: Dmytro Shynkevych <dm.shynk@gmail.com>
    Date: Tue, 27 Dec 2016 13:54:32 -0500
    Subject: [PATCH] Implemented pthread barriers
    
    This is an implementation of pthread barriers pursuant to the relevant specification.
    
    Barriers are essentailly a special case of conditional variables,
    such that all threads waiting on one are woken up when the number of
    waiters reaches a number provided at the initialization of the barrier.
    In view of that, this implementation mimics the implementation of pthread_cond,
    except it is more specialized and self-contained.
    ---
     headers/posix/pthread.h                            |  14 ++
     headers/posix/sys/types.h                          |  14 +-
     headers/private/libroot/pthread_private.h          |   4 +
     src/system/libroot/posix/pthread/Jamfile           |   1 +
     .../libroot/posix/pthread/pthread_barrier.cpp      | 155 +++++++++++++++++++++
     .../system/libroot/posix/pthread_barrier_test.cpp  |  51 +++++++
     6 files changed, 235 insertions(+), 4 deletions(-)
     create mode 100644 src/system/libroot/posix/pthread/pthread_barrier.cpp
     create mode 100644 src/tests/system/libroot/posix/pthread_barrier_test.cpp
    
    diff --git a/headers/posix/pthread.h b/headers/posix/pthread.h
    index 76d3cce2d7..ef7e14596e 100644
    a b extern int pthread_mutexattr_setpshared(pthread_mutexattr_t *mutexAttr,  
    114114    int processShared);
    115115extern int pthread_mutexattr_settype(pthread_mutexattr_t *mutexAttr, int type);
    116116
     117/* barrier functions */
     118extern int pthread_barrier_init(pthread_barrier_t *barrier,
     119    const pthread_barrierattr_t *attr, unsigned count);
     120extern int pthread_barrier_destroy(pthread_barrier_t *barrier);
     121extern int pthread_barrier_wait(pthread_barrier_t *barrier);
     122
     123/* barrier attribute functions */
     124extern int pthread_barrierattr_destroy(pthread_barrierattr_t *attr);
     125extern int pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr,
     126    int *shared);
     127extern int pthread_barrierattr_init(pthread_barrierattr_t *attr);
     128extern int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr,
     129    int shared);
     130
    117131/* condition variable functions */
    118132extern int pthread_cond_destroy(pthread_cond_t *cond);
    119133extern int pthread_cond_init(pthread_cond_t *cond,
  • headers/posix/sys/types.h

    diff --git a/headers/posix/sys/types.h b/headers/posix/sys/types.h
    index 7ae5450630..b09aba569a 100644
    a b typedef struct __timer_t* timer_t;  
    6060
    6161typedef struct  _pthread_thread     *pthread_t;
    6262typedef struct  _pthread_attr       *pthread_attr_t;
     63typedef struct  _pthread_barrier    pthread_barrier_t;
     64typedef struct  _pthread_barrierattr    *pthread_barrierattr_t;
    6365typedef struct  _pthread_mutex      pthread_mutex_t;
    6466typedef struct  _pthread_mutexattr  *pthread_mutexattr_t;
    6567typedef struct  _pthread_cond       pthread_cond_t;
    typedef struct _pthread_once pthread_once_t;  
    6971typedef struct  _pthread_rwlock     pthread_rwlock_t;
    7072typedef struct  _pthread_rwlockattr *pthread_rwlockattr_t;
    7173typedef struct  _pthread_spinlock   pthread_spinlock_t;
    72 /*
    73 typedef struct  _pthread_barrier    *pthread_barrier_t;
    74 typedef struct  _pthread_barrierattr *pthread_barrierattr_t;
    75 */
    7674
    7775struct _pthread_mutex {
    7876    __haiku_std_uint32  flags;
    struct _pthread_mutex {  
    8280    __haiku_std_int32   owner_count;
    8381};
    8482
     83struct _pthread_barrier {
     84    __haiku_std_uint32  flags;
     85    __haiku_std_int32   lock;
     86    __haiku_std_int32   mutex;
     87    __haiku_std_int32   waiter_count;
     88    __haiku_std_int32   waiter_max;
     89};
     90
    8591struct _pthread_cond {
    8692    __haiku_std_uint32  flags;
    8793    __haiku_std_int32   unused;
  • headers/private/libroot/pthread_private.h

    diff --git a/headers/private/libroot/pthread_private.h b/headers/private/libroot/pthread_private.h
    index 169bc8d9bf..953315b60c 100644
    a b typedef struct _pthread_mutexattr {  
    3737    bool        process_shared;
    3838} pthread_mutexattr;
    3939
     40typedef struct _pthread_barrierattr {
     41    bool        process_shared;
     42} pthread_barrierattr;
     43
    4044typedef struct _pthread_attr {
    4145    int32       detach_state;
    4246    int32       sched_priority;
  • src/system/libroot/posix/pthread/Jamfile

    diff --git a/src/system/libroot/posix/pthread/Jamfile b/src/system/libroot/posix/pthread/Jamfile
    index 1968a8e8ee..9a37630f10 100644
    a b for architectureObject in [ MultiArchSubDirSetup ] {  
    1515            pthread.cpp
    1616            pthread_atfork.c
    1717            pthread_attr.c
     18            pthread_barrier.cpp
    1819            pthread_cancel.cpp
    1920            pthread_cleanup.cpp
    2021            pthread_cond.cpp
  • new file src/system/libroot/posix/pthread/pthread_barrier.cpp

    diff --git a/src/system/libroot/posix/pthread/pthread_barrier.cpp b/src/system/libroot/posix/pthread/pthread_barrier.cpp
    new file mode 100644
    index 0000000000..19673a49db
    - +  
     1/*
     2 * Copyright 2016, Dmytro Shynkevych, dm.shynk@gmail.com
     3 * Distributed under the terms of the MIT license.
     4 */
     5
     6
     7#include <pthread.h>
     8#include "pthread_private.h"
     9
     10#include <stdlib.h>
     11#include <stdio.h>
     12#include <string.h>
     13
     14#include <syscall_utils.h>
     15#include <syscalls.h>
     16#include <user_mutex_defs.h>
     17
     18#define BARRIER_FLAG_SHARED 0x80000000
     19
     20static const pthread_barrierattr pthread_barrierattr_default = {
     21    /* .process_shared = */ false
     22};
     23
     24
     25int
     26pthread_barrier_init(pthread_barrier_t* barrier,
     27    const pthread_barrierattr_t* _attr, unsigned count)
     28{
     29    const pthread_barrierattr* attr = _attr != NULL
     30        ? *_attr : &pthread_barrierattr_default;
     31
     32    if (barrier == NULL || attr == NULL || count < 1)
     33        return B_BAD_VALUE;
     34
     35    barrier->flags = attr->process_shared ? BARRIER_FLAG_SHARED : 0;
     36    barrier->lock = 0;
     37    barrier->mutex = 0;
     38    barrier->waiter_count = 0;
     39    barrier->waiter_max = count;
     40
     41    return B_OK;
     42}
     43
     44
     45int
     46pthread_barrier_wait(pthread_barrier_t* barrier)
     47{
     48    if (barrier == NULL)
     49        return B_BAD_VALUE;
     50
     51    // Enter critical region: lock the mutex
     52    int32 status = atomic_or((int32*)&barrier->mutex, B_USER_MUTEX_LOCKED);
     53
     54    // If already locked, call the kernel
     55    if (status & (B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING)) {
     56        do {
     57            status = _kern_mutex_lock((int32*)&barrier->mutex, NULL, 0, 0);
     58        } while (status == B_INTERRUPTED);
     59
     60        if (status != B_OK)
     61            return status;
     62    }
     63
     64    barrier->waiter_count++;
     65
     66    // If this thread is the last to arrive
     67    if (barrier->waiter_count == barrier->waiter_max) {
     68        // Let other threads exit the do...while loop
     69        barrier->waiter_count = 0;
     70
     71        // Wake up everyone trying to acquire the barrier lock
     72        _kern_mutex_unlock((int32*)&barrier->lock, B_USER_MUTEX_UNBLOCK_ALL);
     73
     74        // Exit critical region: unlock the mutex
     75        int32 status = atomic_and((int32*)&barrier->mutex,
     76                ~(int32)B_USER_MUTEX_LOCKED);
     77
     78        if (status & B_USER_MUTEX_WAITING)
     79            _kern_mutex_unlock((int32*)&barrier->mutex, 0);
     80
     81        // Inform the calling thread that it arrived last
     82        return PTHREAD_BARRIER_SERIAL_THREAD;
     83    } else {
     84        do {
     85            // Wait indefinitely trying to acquire the barrier lock.
     86            // Other threads may now enter (mutex is unlocked).
     87            _kern_mutex_switch_lock((int32*)&barrier->mutex,
     88                    (int32*)&barrier->lock, "barrier wait", 0, 0);
     89        } while (barrier->waiter_count != 0);
     90
     91        // This thread did not arrive last
     92        return 0;
     93    }
     94}
     95
     96
     97int
     98pthread_barrier_destroy(pthread_barrier_t* barrier)
     99{
     100    // No dynamic resources to free
     101    return B_OK;
     102}
     103
     104
     105int
     106pthread_barrierattr_init(pthread_barrierattr_t* _attr)
     107{
     108    pthread_barrierattr* attr = (pthread_barrierattr*)malloc(
     109        sizeof(pthread_barrierattr));
     110
     111    if (attr == NULL)
     112        return B_NO_MEMORY;
     113
     114    *attr = pthread_barrierattr_default;
     115    *_attr = attr;
     116
     117    return B_OK;
     118}
     119
     120
     121int
     122pthread_barrierattr_destroy(pthread_barrierattr_t* _attr)
     123{
     124    pthread_barrierattr* attr = _attr != NULL ? *_attr : NULL;
     125
     126    if (attr == NULL)
     127        return B_BAD_VALUE;
     128
     129    free(attr);
     130
     131    return B_OK;
     132}
     133
     134
     135int
     136pthread_barrierattr_getpshared(const pthread_barrierattr_t* _attr, int* shared)
     137{
     138    pthread_barrierattr* attr = *_attr;
     139
     140    *shared = attr->process_shared
     141        ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE;
     142
     143    return B_OK;
     144}
     145
     146
     147int
     148pthread_barrierattr_setpshared(pthread_barrierattr_t* _attr, int shared)
     149{
     150    pthread_barrierattr* attr = *_attr;
     151
     152    attr->process_shared = shared == PTHREAD_PROCESS_SHARED;
     153
     154    return 0;
     155}
  • new file src/tests/system/libroot/posix/pthread_barrier_test.cpp

    diff --git a/src/tests/system/libroot/posix/pthread_barrier_test.cpp b/src/tests/system/libroot/posix/pthread_barrier_test.cpp
    new file mode 100644
    index 0000000000..d9afc156a1
    - +  
     1#include <stdio.h>
     2#include <stdlib.h>
     3#include <unistd.h>
     4#include <pthread.h>
     5
     6#define THREAD_COUNT 10
     7#define CYCLES 2
     8
     9pthread_barrier_t mybarrier;
     10
     11void* threadFn(void* id_ptr)
     12{
     13    int thread_id = *(int*)id_ptr;
     14
     15    for (int i = 0; i < CYCLES; ++i) {
     16        int wait_sec = 1 + rand() % 10;
     17        printf("thread %d: Wait %d seconds.\n", thread_id, wait_sec);
     18        sleep(wait_sec);
     19        printf("thread %d: Waiting on barrier...\n", thread_id);
     20
     21        int status = pthread_barrier_wait(&mybarrier);
     22        if (status == PTHREAD_BARRIER_SERIAL_THREAD)
     23            printf("thread %d: serial thread.\n", thread_id);
     24        printf("thread %d: Finished!\n", thread_id);
     25    }
     26
     27    return NULL;
     28}
     29
     30
     31int main()
     32{
     33    pthread_t ids[THREAD_COUNT];
     34    int short_ids[THREAD_COUNT];
     35
     36    srand(time(NULL));
     37    pthread_barrier_init(&mybarrier, NULL, THREAD_COUNT);
     38
     39    for (int i = 0; i < THREAD_COUNT; i++) {
     40        short_ids[i] = i;
     41        pthread_create(&ids[i], NULL, threadFn, &short_ids[i]);
     42    }
     43
     44    for (int i = 0; i < THREAD_COUNT; i++)
     45        pthread_join(ids[i], NULL);
     46
     47    pthread_barrier_destroy(&mybarrier);
     48
     49    return 0;
     50}
     51