Ticket #5694: 0001-Implemented-pthread-barriers.patch
File 0001-Implemented-pthread-barriers.patch, 9.5 KB (added by , 7 years ago) |
---|
-
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, 114 114 int processShared); 115 115 extern int pthread_mutexattr_settype(pthread_mutexattr_t *mutexAttr, int type); 116 116 117 /* barrier functions */ 118 extern int pthread_barrier_init(pthread_barrier_t *barrier, 119 const pthread_barrierattr_t *attr, unsigned count); 120 extern int pthread_barrier_destroy(pthread_barrier_t *barrier); 121 extern int pthread_barrier_wait(pthread_barrier_t *barrier); 122 123 /* barrier attribute functions */ 124 extern int pthread_barrierattr_destroy(pthread_barrierattr_t *attr); 125 extern int pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr, 126 int *shared); 127 extern int pthread_barrierattr_init(pthread_barrierattr_t *attr); 128 extern int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, 129 int shared); 130 117 131 /* condition variable functions */ 118 132 extern int pthread_cond_destroy(pthread_cond_t *cond); 119 133 extern 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; 60 60 61 61 typedef struct _pthread_thread *pthread_t; 62 62 typedef struct _pthread_attr *pthread_attr_t; 63 typedef struct _pthread_barrier pthread_barrier_t; 64 typedef struct _pthread_barrierattr *pthread_barrierattr_t; 63 65 typedef struct _pthread_mutex pthread_mutex_t; 64 66 typedef struct _pthread_mutexattr *pthread_mutexattr_t; 65 67 typedef struct _pthread_cond pthread_cond_t; … … typedef struct _pthread_once pthread_once_t; 69 71 typedef struct _pthread_rwlock pthread_rwlock_t; 70 72 typedef struct _pthread_rwlockattr *pthread_rwlockattr_t; 71 73 typedef struct _pthread_spinlock pthread_spinlock_t; 72 /*73 typedef struct _pthread_barrier *pthread_barrier_t;74 typedef struct _pthread_barrierattr *pthread_barrierattr_t;75 */76 74 77 75 struct _pthread_mutex { 78 76 __haiku_std_uint32 flags; … … struct _pthread_mutex { 82 80 __haiku_std_int32 owner_count; 83 81 }; 84 82 83 struct _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 85 91 struct _pthread_cond { 86 92 __haiku_std_uint32 flags; 87 93 __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 { 37 37 bool process_shared; 38 38 } pthread_mutexattr; 39 39 40 typedef struct _pthread_barrierattr { 41 bool process_shared; 42 } pthread_barrierattr; 43 40 44 typedef struct _pthread_attr { 41 45 int32 detach_state; 42 46 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 ] { 15 15 pthread.cpp 16 16 pthread_atfork.c 17 17 pthread_attr.c 18 pthread_barrier.cpp 18 19 pthread_cancel.cpp 19 20 pthread_cleanup.cpp 20 21 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 20 static const pthread_barrierattr pthread_barrierattr_default = { 21 /* .process_shared = */ false 22 }; 23 24 25 int 26 pthread_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 45 int 46 pthread_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 97 int 98 pthread_barrier_destroy(pthread_barrier_t* barrier) 99 { 100 // No dynamic resources to free 101 return B_OK; 102 } 103 104 105 int 106 pthread_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 121 int 122 pthread_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 135 int 136 pthread_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 147 int 148 pthread_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 9 pthread_barrier_t mybarrier; 10 11 void* 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 31 int 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