aboutsummaryrefslogtreecommitdiff
path: root/vendor/zgui/libs/winpthreads/src/rwlock.c
diff options
context:
space:
mode:
authorNic Gaffney <gaffney_nic@protonmail.com>2024-06-12 21:15:52 -0500
committerNic Gaffney <gaffney_nic@protonmail.com>2024-06-12 21:15:52 -0500
commit963fae202108acd0498349e872e4811fa6c6aba0 (patch)
tree1a7d5b6ee837700819d8f6f5a2484342a0ab6ec1 /vendor/zgui/libs/winpthreads/src/rwlock.c
parent6084001df845815efd9c0eb712acf4fd9311ce36 (diff)
downloadparticle-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.c537
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;
+}