diff options
| author | Nic Gaffney <gaffney_nic@protonmail.com> | 2024-06-12 21:15:52 -0500 |
|---|---|---|
| committer | Nic Gaffney <gaffney_nic@protonmail.com> | 2024-06-12 21:15:52 -0500 |
| commit | 963fae202108acd0498349e872e4811fa6c6aba0 (patch) | |
| tree | 1a7d5b6ee837700819d8f6f5a2484342a0ab6ec1 /vendor/zgui/libs/winpthreads/src/rwlock.c | |
| parent | 6084001df845815efd9c0eb712acf4fd9311ce36 (diff) | |
| download | particle-sim-963fae202108acd0498349e872e4811fa6c6aba0.tar.gz | |
Added imgui for configuration
Diffstat (limited to 'vendor/zgui/libs/winpthreads/src/rwlock.c')
| -rw-r--r-- | vendor/zgui/libs/winpthreads/src/rwlock.c | 537 |
1 files changed, 537 insertions, 0 deletions
diff --git a/vendor/zgui/libs/winpthreads/src/rwlock.c b/vendor/zgui/libs/winpthreads/src/rwlock.c new file mode 100644 index 0000000..76669df --- /dev/null +++ b/vendor/zgui/libs/winpthreads/src/rwlock.c @@ -0,0 +1,537 @@ +/* + 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 "thread.h" +#include "ref.h" +#include "rwlock.h" +#include "misc.h" + +static pthread_spinlock_t rwl_global = PTHREAD_SPINLOCK_INITIALIZER; + +static WINPTHREADS_ATTRIBUTE((noinline)) int rwlock_static_init(pthread_rwlock_t *rw); + +static WINPTHREADS_ATTRIBUTE((noinline)) int rwl_unref(volatile pthread_rwlock_t *rwl, int res) +{ + pthread_spin_lock(&rwl_global); +#ifdef WINPTHREAD_DBG + assert((((rwlock_t *)*rwl)->valid == LIFE_RWLOCK) && (((rwlock_t *)*rwl)->busy > 0)); +#endif + ((rwlock_t *)*rwl)->busy--; + pthread_spin_unlock(&rwl_global); + return res; +} + +static WINPTHREADS_ATTRIBUTE((noinline)) int rwl_ref(pthread_rwlock_t *rwl, int f ) +{ + int r = 0; + if (STATIC_RWL_INITIALIZER(*rwl)) { + r = rwlock_static_init(rwl); + if (r != 0 && r != EBUSY) + return r; + } + pthread_spin_lock(&rwl_global); + + if (!rwl || !*rwl || ((rwlock_t *)*rwl)->valid != LIFE_RWLOCK) r = EINVAL; + else { + ((rwlock_t *)*rwl)->busy ++; + } + + pthread_spin_unlock(&rwl_global); + + return r; +} + +static WINPTHREADS_ATTRIBUTE((noinline)) int rwl_ref_unlock(pthread_rwlock_t *rwl ) +{ + int r = 0; + + pthread_spin_lock(&rwl_global); + + if (!rwl || !*rwl || ((rwlock_t *)*rwl)->valid != LIFE_RWLOCK) r = EINVAL; + else if (STATIC_RWL_INITIALIZER(*rwl)) r= EPERM; + else { + ((rwlock_t *)*rwl)->busy ++; + } + + pthread_spin_unlock(&rwl_global); + + return r; +} + +static WINPTHREADS_ATTRIBUTE((noinline)) int rwl_ref_destroy(pthread_rwlock_t *rwl, pthread_rwlock_t *rDestroy ) +{ + int r = 0; + + *rDestroy = (pthread_rwlock_t)NULL; + pthread_spin_lock(&rwl_global); + + if (!rwl || !*rwl) r = EINVAL; + else { + rwlock_t *r_ = (rwlock_t *)*rwl; + if (STATIC_RWL_INITIALIZER(*rwl)) *rwl = (pthread_rwlock_t)NULL; + else if (r_->valid != LIFE_RWLOCK) r = EINVAL; + else if (r_->busy) r = EBUSY; + else { + *rDestroy = *rwl; + *rwl = (pthread_rwlock_t)NULL; + } + } + + pthread_spin_unlock(&rwl_global); + return r; +} + +static int rwlock_gain_both_locks(rwlock_t *rwlock) +{ + int ret; + ret = pthread_mutex_lock(&rwlock->mex); + if (ret != 0) + return ret; + ret = pthread_mutex_lock(&rwlock->mcomplete); + if (ret != 0) + pthread_mutex_unlock(&rwlock->mex); + return ret; +} + +static int rwlock_free_both_locks(rwlock_t *rwlock, int last_fail) +{ + int ret, ret2; + ret = pthread_mutex_unlock(&rwlock->mcomplete); + ret2 = pthread_mutex_unlock(&rwlock->mex); + if (last_fail && ret2 != 0) + ret = ret2; + else if (!last_fail && !ret) + ret = ret2; + return ret; +} + +#ifdef WINPTHREAD_DBG +static int print_state = 0; +void rwl_print_set(int state) +{ + print_state = state; +} + +void rwl_print(volatile pthread_rwlock_t *rwl, char *txt) +{ + if (!print_state) return; + rwlock_t *r = (rwlock_t *)*rwl; + if (r == NULL) { + printf("RWL%p %lu %s\n",(void *)*rwl,GetCurrentThreadId(),txt); + } else { + printf("RWL%p %lu V=%0X B=%d r=%ld w=%ld L=%p %s\n", + (void *)*rwl, + GetCurrentThreadId(), + (int)r->valid, + (int)r->busy, + 0L,0L,NULL,txt); + } +} +#endif + +static pthread_spinlock_t cond_locked = PTHREAD_SPINLOCK_INITIALIZER; + +static WINPTHREADS_ATTRIBUTE((noinline)) int rwlock_static_init(pthread_rwlock_t *rw) +{ + int r; + pthread_spin_lock(&cond_locked); + if (*rw != PTHREAD_RWLOCK_INITIALIZER) + { + pthread_spin_unlock(&cond_locked); + return EINVAL; + } + r = pthread_rwlock_init (rw, NULL); + pthread_spin_unlock(&cond_locked); + + return r; +} + +int pthread_rwlock_init (pthread_rwlock_t *rwlock_, const pthread_rwlockattr_t *attr) +{ + rwlock_t *rwlock; + int r; + + if(!rwlock_) + return EINVAL; + *rwlock_ = (pthread_rwlock_t)NULL; + if ((rwlock = calloc(1, sizeof(*rwlock))) == NULL) + return ENOMEM; + rwlock->valid = DEAD_RWLOCK; + + rwlock->nex_count = rwlock->nsh_count = rwlock->ncomplete = 0; + if ((r = pthread_mutex_init (&rwlock->mex, NULL)) != 0) + { + free(rwlock); + return r; + } + if ((r = pthread_mutex_init (&rwlock->mcomplete, NULL)) != 0) + { + pthread_mutex_destroy(&rwlock->mex); + free(rwlock); + return r; + } + if ((r = pthread_cond_init (&rwlock->ccomplete, NULL)) != 0) + { + pthread_mutex_destroy(&rwlock->mex); + pthread_mutex_destroy (&rwlock->mcomplete); + free(rwlock); + return r; + } + rwlock->valid = LIFE_RWLOCK; + *rwlock_ = (pthread_rwlock_t)rwlock; + return r; +} + +int pthread_rwlock_destroy (pthread_rwlock_t *rwlock_) +{ + rwlock_t *rwlock; + pthread_rwlock_t rDestroy; + int r, r2; + + pthread_spin_lock(&cond_locked); + r = rwl_ref_destroy(rwlock_,&rDestroy); + pthread_spin_unlock(&cond_locked); + + if(r) return r; + if(!rDestroy) return 0; /* destroyed a (still) static initialized rwl */ + + rwlock = (rwlock_t *)rDestroy; + r = rwlock_gain_both_locks (rwlock); + if (r != 0) + { + *rwlock_ = rDestroy; + return r; + } + if (rwlock->nsh_count > rwlock->ncomplete || rwlock->nex_count > 0) + { + *rwlock_ = rDestroy; + r = rwlock_free_both_locks(rwlock, 1); + if (!r) + r = EBUSY; + return r; + } + rwlock->valid = DEAD_RWLOCK; + r = rwlock_free_both_locks(rwlock, 0); + if (r != 0) { *rwlock_ = rDestroy; return r; } + + r = pthread_cond_destroy(&rwlock->ccomplete); + r2 = pthread_mutex_destroy(&rwlock->mex); + if (!r) r = r2; + r2 = pthread_mutex_destroy(&rwlock->mcomplete); + if (!r) r = r2; + rwlock->valid = DEAD_RWLOCK; + free((void *)rDestroy); + return 0; +} + +int pthread_rwlock_rdlock (pthread_rwlock_t *rwlock_) +{ + rwlock_t *rwlock; + int ret; + + /* pthread_testcancel(); */ + + ret = rwl_ref(rwlock_,0); + if(ret != 0) return ret; + + rwlock = (rwlock_t *)*rwlock_; + + ret = pthread_mutex_lock(&rwlock->mex); + if (ret != 0) return rwl_unref(rwlock_, ret); + InterlockedIncrement((long*)&rwlock->nsh_count); + if (rwlock->nsh_count == INT_MAX) + { + ret = pthread_mutex_lock(&rwlock->mcomplete); + if (ret != 0) + { + pthread_mutex_unlock(&rwlock->mex); + return rwl_unref(rwlock_,ret); + } + rwlock->nsh_count -= rwlock->ncomplete; + rwlock->ncomplete = 0; + ret = rwlock_free_both_locks(rwlock, 0); + return rwl_unref(rwlock_, ret); + } + ret = pthread_mutex_unlock(&rwlock->mex); + return rwl_unref(rwlock_, ret); +} + +int pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock_, const struct timespec *ts) +{ + rwlock_t *rwlock; + int ret; + + /* pthread_testcancel(); */ + + ret = rwl_ref(rwlock_,0); + if(ret != 0) return ret; + + rwlock = (rwlock_t *)*rwlock_; + if ((ret = pthread_mutex_timedlock (&rwlock->mex, ts)) != 0) + return rwl_unref(rwlock_, ret); + InterlockedIncrement(&rwlock->nsh_count); + if (rwlock->nsh_count == INT_MAX) + { + ret = pthread_mutex_timedlock(&rwlock->mcomplete, ts); + if (ret != 0) + { + if (ret == ETIMEDOUT) + InterlockedIncrement(&rwlock->ncomplete); + pthread_mutex_unlock(&rwlock->mex); + return rwl_unref(rwlock_, ret); + } + rwlock->nsh_count -= rwlock->ncomplete; + rwlock->ncomplete = 0; + ret = rwlock_free_both_locks(rwlock, 0); + return rwl_unref(rwlock_, ret); + } + ret = pthread_mutex_unlock(&rwlock->mex); + return rwl_unref(rwlock_, ret); +} + +int pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock_) +{ + rwlock_t *rwlock; + int ret; + + ret = rwl_ref(rwlock_,RWL_TRY); + if(ret != 0) return ret; + + rwlock = (rwlock_t *)*rwlock_; + ret = pthread_mutex_trylock(&rwlock->mex); + if (ret != 0) + return rwl_unref(rwlock_, ret); + InterlockedIncrement(&rwlock->nsh_count); + if (rwlock->nsh_count == INT_MAX) + { + ret = pthread_mutex_lock(&rwlock->mcomplete); + if (ret != 0) + { + pthread_mutex_unlock(&rwlock->mex); + return rwl_unref(rwlock_, ret); + } + rwlock->nsh_count -= rwlock->ncomplete; + rwlock->ncomplete = 0; + ret = rwlock_free_both_locks(rwlock, 0); + return rwl_unref(rwlock_, ret); + } + ret = pthread_mutex_unlock(&rwlock->mex); + return rwl_unref(rwlock_,ret); +} + +int pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock_) +{ + rwlock_t *rwlock; + int ret; + + ret = rwl_ref(rwlock_,RWL_TRY); + if(ret != 0) return ret; + + rwlock = (rwlock_t *)*rwlock_; + ret = pthread_mutex_trylock (&rwlock->mex); + if (ret != 0) + return rwl_unref(rwlock_, ret); + ret = pthread_mutex_trylock(&rwlock->mcomplete); + if (ret != 0) + { + int r1 = pthread_mutex_unlock(&rwlock->mex); + if (r1 != 0) + ret = r1; + return rwl_unref(rwlock_, ret); + } + if (rwlock->nex_count != 0) + return rwl_unref(rwlock_, EBUSY); + if (rwlock->ncomplete > 0) + { + rwlock->nsh_count -= rwlock->ncomplete; + rwlock->ncomplete = 0; + } + if (rwlock->nsh_count > 0) + { + ret = rwlock_free_both_locks(rwlock, 0); + if (!ret) + ret = EBUSY; + return rwl_unref(rwlock_, ret); + } + rwlock->nex_count = 1; + return rwl_unref(rwlock_, 0); +} + +int pthread_rwlock_unlock (pthread_rwlock_t *rwlock_) +{ + rwlock_t *rwlock; + int ret; + + ret = rwl_ref_unlock(rwlock_); + if(ret != 0) return ret; + + rwlock = (rwlock_t *)*rwlock_; + if (rwlock->nex_count == 0) + { + ret = pthread_mutex_lock(&rwlock->mcomplete); + if (!ret) + { + int r1; + InterlockedIncrement(&rwlock->ncomplete); + if (rwlock->ncomplete == 0) + ret = pthread_cond_signal(&rwlock->ccomplete); + r1 = pthread_mutex_unlock(&rwlock->mcomplete); + if (!ret) + ret = r1; + } + } + else + { + InterlockedDecrement(&rwlock->nex_count); + ret = rwlock_free_both_locks(rwlock, 0); + } + return rwl_unref(rwlock_, ret); +} + +static void st_cancelwrite (void *arg) +{ + rwlock_t *rwlock = (rwlock_t *)arg; + + rwlock->nsh_count = - rwlock->ncomplete; + rwlock->ncomplete = 0; + rwlock_free_both_locks(rwlock, 0); +} + +int pthread_rwlock_wrlock (pthread_rwlock_t *rwlock_) +{ + rwlock_t *rwlock; + int ret; + + /* pthread_testcancel(); */ + ret = rwl_ref(rwlock_,0); + if(ret != 0) return ret; + + rwlock = (rwlock_t *)*rwlock_; + ret = rwlock_gain_both_locks(rwlock); + if (ret != 0) + return rwl_unref(rwlock_,ret); + + if (rwlock->nex_count == 0) + { + if (rwlock->ncomplete > 0) + { + rwlock->nsh_count -= rwlock->ncomplete; + rwlock->ncomplete = 0; + } + if (rwlock->nsh_count > 0) + { + rwlock->ncomplete = -rwlock->nsh_count; + pthread_cleanup_push(st_cancelwrite, (void *) rwlock); + do { + ret = pthread_cond_wait(&rwlock->ccomplete, &rwlock->mcomplete); + } while (!ret && rwlock->ncomplete < 0); + + pthread_cleanup_pop(!ret ? 0 : 1); + if (!ret) + rwlock->nsh_count = 0; + } + } + if(!ret) + InterlockedIncrement((long*)&rwlock->nex_count); + return rwl_unref(rwlock_,ret); +} + +int pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock_, const struct timespec *ts) +{ + int ret; + rwlock_t *rwlock; + + /* pthread_testcancel(); */ + if (!rwlock_ || !ts) + return EINVAL; + if ((ret = rwl_ref(rwlock_,0)) != 0) + return ret; + rwlock = (rwlock_t *)*rwlock_; + + ret = pthread_mutex_timedlock(&rwlock->mex, ts); + if (ret != 0) + return rwl_unref(rwlock_,ret); + ret = pthread_mutex_timedlock (&rwlock->mcomplete, ts); + if (ret != 0) + { + pthread_mutex_unlock(&rwlock->mex); + return rwl_unref(rwlock_,ret); + } + if (rwlock->nex_count == 0) + { + if (rwlock->ncomplete > 0) + { + rwlock->nsh_count -= rwlock->ncomplete; + rwlock->ncomplete = 0; + } + if (rwlock->nsh_count > 0) + { + rwlock->ncomplete = -rwlock->nsh_count; + pthread_cleanup_push(st_cancelwrite, (void *) rwlock); + do { + ret = pthread_cond_timedwait(&rwlock->ccomplete, &rwlock->mcomplete, ts); + } while (rwlock->ncomplete < 0 && !ret); + pthread_cleanup_pop(!ret ? 0 : 1); + + if (!ret) + rwlock->nsh_count = 0; + } + } + if(!ret) + InterlockedIncrement((long*)&rwlock->nex_count); + return rwl_unref(rwlock_,ret); +} + +int pthread_rwlockattr_destroy(pthread_rwlockattr_t *a) +{ + if (!a) + return EINVAL; + return 0; +} + +int pthread_rwlockattr_init(pthread_rwlockattr_t *a) +{ + if (!a) + return EINVAL; + *a = PTHREAD_PROCESS_PRIVATE; + return 0; +} + +int pthread_rwlockattr_getpshared(pthread_rwlockattr_t *a, int *s) +{ + if (!a || !s) + return EINVAL; + *s = *a; + return 0; +} + +int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *a, int s) +{ + if (!a || (s != PTHREAD_PROCESS_SHARED && s != PTHREAD_PROCESS_PRIVATE)) + return EINVAL; + *a = s; + return 0; +} |
