#include "pthread_impl.h" #include static inline __cnd_t* __cnd_init(__cnd_t *c, __mtx_t *m) { if (c) { *c = (__cnd_t) { .rfs = 2, .mtx = m, }; } if (m) __mtx_addref(m); return c; } static inline void __cnd_delete(__cnd_t *c) { if (c) { __mtx_unref(c->mtx); c->mtx = 0; free(c); } } void __cnd_unref(__cnd_t *c) { if (c) { if (a_fetch_add(&c->rfs, -1) == 1) { __cnd_delete(c); } } } static inline __cnd_t* __cnd_getref_def(cnd_t *cond, __mtx_t* m, __cnd_t* def) { __cnd_t * ret; __mtx_t * prev = 0; /* Critical section protected by spin lock . */ a_splck(&cond->_cx_lock); ret = cond->_cx_cnd; if (ret) { __cnd_addref(ret); if (m && ret->mtx != m) { prev = ret->mtx; __mtx_addref(m); ret->mtx = m; } } else if (def) { ret = def; cond->_cx_cnd = def; } a_spunl(&cond->_cx_lock); if (prev) __mtx_unref(prev); return ret; } __cnd_t* __cnd_getref(cnd_t *cond, __mtx_t * m) { __cnd_t * ret = __cnd_getref_def(cond, m, 0); if (!ret) { __cnd_t * new = __cnd_init(malloc(sizeof *ret), m); if (new) { ret = __cnd_getref_def(cond, m, new); /* somebody sneaked in between the first and second call */ if (ret != new) __cnd_delete(new); } } return ret; }