diff options
Diffstat (limited to 'vendor/zgui/libs/winpthreads/src/barrier.c')
| -rw-r--r-- | vendor/zgui/libs/winpthreads/src/barrier.c | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/vendor/zgui/libs/winpthreads/src/barrier.c b/vendor/zgui/libs/winpthreads/src/barrier.c new file mode 100644 index 0000000..e973aaa --- /dev/null +++ b/vendor/zgui/libs/winpthreads/src/barrier.c @@ -0,0 +1,246 @@ +/* + Copyright (c) 2011-2016 mingw-w64 project + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include <windows.h> +#include <stdio.h> +#include <malloc.h> +#include "pthread.h" +#include "barrier.h" +#include "ref.h" +#include "misc.h" + +static pthread_spinlock_t barrier_global = PTHREAD_SPINLOCK_INITIALIZER; + +static WINPTHREADS_ATTRIBUTE((noinline)) int +barrier_unref(volatile pthread_barrier_t *barrier, int res) +{ + pthread_spin_lock(&barrier_global); +#ifdef WINPTHREAD_DBG + assert((((barrier_t *)*barrier)->valid == LIFE_BARRIER) && (((barrier_t *)*barrier)->busy > 0)); +#endif + ((barrier_t *)*barrier)->busy -= 1; + pthread_spin_unlock(&barrier_global); + return res; +} + +static WINPTHREADS_ATTRIBUTE((noinline)) int barrier_ref(volatile pthread_barrier_t *barrier) +{ + int r = 0; + pthread_spin_lock(&barrier_global); + + if (!barrier || !*barrier || ((barrier_t *)*barrier)->valid != LIFE_BARRIER) r = EINVAL; + else { + ((barrier_t *)*barrier)->busy += 1; + } + + pthread_spin_unlock(&barrier_global); + + return r; +} + +static WINPTHREADS_ATTRIBUTE((noinline)) int +barrier_ref_destroy(volatile pthread_barrier_t *barrier, pthread_barrier_t *bDestroy) +{ + int r = 0; + + *bDestroy = NULL; + pthread_spin_lock(&barrier_global); + + if (!barrier || !*barrier || ((barrier_t *)*barrier)->valid != LIFE_BARRIER) r = EINVAL; + else { + barrier_t *b_ = (barrier_t *)*barrier; + if (b_->busy) r = EBUSY; + else { + *bDestroy = *barrier; + *barrier = NULL; + } + } + + pthread_spin_unlock(&barrier_global); + return r; +} + +static WINPTHREADS_ATTRIBUTE((noinline)) void +barrier_ref_set (volatile pthread_barrier_t *barrier, void *v) +{ + pthread_spin_lock(&barrier_global); + *barrier = v; + pthread_spin_unlock(&barrier_global); +} + +int pthread_barrier_destroy(pthread_barrier_t *b_) +{ + pthread_barrier_t bDestroy; + barrier_t *b; + int r; + + while ((r = barrier_ref_destroy(b_,&bDestroy)) == EBUSY) + Sleep(0); + + if (r) + return r; + + b = (barrier_t *)bDestroy; + + pthread_mutex_lock(&b->m); + + if (sem_destroy(&b->sems[0]) != 0) + { + /* Could this happen? */ + *b_ = bDestroy; + pthread_mutex_unlock (&b->m); + return EBUSY; + } + if (sem_destroy(&b->sems[1]) != 0) + { + sem_init (&b->sems[0], b->share, 0); + *b_ = bDestroy; + pthread_mutex_unlock (&b->m); + return -1; + } + pthread_mutex_unlock(&b->m); + if(pthread_mutex_destroy(&b->m) != 0) { + sem_init (&b->sems[0], b->share, 0); + sem_init (&b->sems[1], b->share, 0); + *b_ = bDestroy; + return -1; + } + b->valid = DEAD_BARRIER; + free(bDestroy); + return 0; + +} + +int +pthread_barrier_init (pthread_barrier_t *b_, const void *attr, + unsigned int count) +{ + barrier_t *b; + + if (!count || !b_) + return EINVAL; + + if ((b = (pthread_barrier_t)calloc(1,sizeof(*b))) == NULL) + return ENOMEM; + if (!attr || *((int **)attr) == NULL) + b->share = PTHREAD_PROCESS_PRIVATE; + else + memcpy (&b->share, *((void **) attr), sizeof (int)); + b->total = count; + b->count = count; + b->valid = LIFE_BARRIER; + b->sel = 0; + + if (pthread_mutex_init(&b->m, NULL) != 0) + { + free (b); + return ENOMEM; + } + + if (sem_init(&b->sems[0], b->share, 0) != 0) + { + pthread_mutex_destroy(&b->m); + free (b); + return ENOMEM; + } + if (sem_init(&b->sems[1], b->share, 0) != 0) + { + pthread_mutex_destroy(&b->m); + sem_destroy(&b->sems[0]); + free (b); + return ENOMEM; + } + barrier_ref_set (b_,b); + + return 0; +} + +int pthread_barrier_wait(pthread_barrier_t *b_) +{ + long sel; + int r, e, rslt; + barrier_t *b; + + r = barrier_ref(b_); + if(r) return r; + + b = (barrier_t *)*b_; + + if ((r = pthread_mutex_lock(&b->m)) != 0) return barrier_unref(b_,EINVAL); + sel = b->sel; + InterlockedDecrement((long*)&b->total); + if (b->total == 0) + { + b->total = b->count; + b->sel = (sel != 0 ? 0 : 1); + e = 1; + rslt = PTHREAD_BARRIER_SERIAL_THREAD; + r = (b->count > 1 ? sem_post_multiple (&b->sems[sel], b->count - 1) : 0); + } + else { e = 0; rslt= 0; } + pthread_mutex_unlock(&b->m); + if (!e) + r = sem_wait(&b->sems[sel]); + + if (!r) r = rslt; + return barrier_unref(b_,r); +} + +int pthread_barrierattr_init(void **attr) +{ + int *p; + + if ((p = (int *) calloc (1, sizeof (int))) == NULL) + return ENOMEM; + + *p = PTHREAD_PROCESS_PRIVATE; + *attr = p; + + return 0; +} + +int pthread_barrierattr_destroy(void **attr) +{ + void *p; + if (!attr || (p = *attr) == NULL) + return EINVAL; + *attr = NULL; + free (p); + return 0; +} + +int pthread_barrierattr_setpshared(void **attr, int s) +{ + if (!attr || *attr == NULL + || (s != PTHREAD_PROCESS_SHARED && s != PTHREAD_PROCESS_PRIVATE)) + return EINVAL; + memcpy (*attr, &s, sizeof (int)); + return 0; +} + +int pthread_barrierattr_getpshared(void **attr, int *s) +{ + if (!attr || !s || *attr == NULL) + return EINVAL; + memcpy (s, *attr, sizeof (int)); + return 0; +} |
