#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, .wts = 1, .seq = 0, }; } if (m) __mtx_addref(m); return c; } static inline void __cnd_delete(__cnd_t *c) __attribute__((nonnull(1))); static inline void __cnd_delete(__cnd_t *c) { __mtx_unref(c->mtx); c->mtx = 0; free(c); } void __cnd_unref(__cnd_t *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, int * seq) __attribute__((nonnull(1,2))); static inline __cnd_t* __cnd_getref_def(cnd_t *cond, __mtx_t* m, __cnd_t* def, int * seq) { __cnd_t * ret; /* Critical section protected by lock. */ __lock(&cond->_cx_lock); ret = cond->_cx_cnd; if (ret) { if (m) { /* Has the cnd just been initialized? */ if (!ret->mtx) { __mtx_addref(m); ret->mtx = m; /* If not, is it consistent with previous usage? */ } else if (ret->mtx != m) { ret = 0; goto UNLOCK; } } ++ret->wts; __cnd_addref(ret); *seq = ret->seq; } else if (def) { ret = def; cond->_cx_cnd = def; } UNLOCK: __unlock(&cond->_cx_lock); return ret; } __cnd_t* __cnd_getref(cnd_t *cond, __mtx_t * m, int * seq) { __cnd_t * ret = __cnd_getref_def(cond, m, 0, seq); if (!ret) { __cnd_t * new = __cnd_init(malloc(sizeof *ret), m); if (new) { ret = __cnd_getref_def(cond, m, new, seq); /* somebody sneaked in between the first and second call */ if (ret != new) __cnd_delete(new); } } return ret; }