// // Copyright 2016 Garrett D'Amore // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this // file was obtained (LICENSE.txt). A copy of the license may also be // found online at https://opensource.org/licenses/MIT. // // POSIX synchronization (mutexes and condition variables). This uses // pthreads. #include "core/nng_impl.h" #ifdef PLATFORM_POSIX_SYNCH #include #include #include extern pthread_condattr_t nni_cvattr; extern pthread_mutexattr_t nni_mxattr; int nni_mutex_init(nni_mutex *mp) { if (pthread_mutex_init(&mp->mx, &nni_mxattr) != 0) { return (NNG_ENOMEM); } return (0); } void nni_mutex_fini(nni_mutex *mp) { int rv; if ((rv = pthread_mutex_destroy(&mp->mx)) != 0) { nni_panic("pthread_mutex_destroy failed: %s", strerror(rv)); } } void nni_mutex_enter(nni_mutex *m) { int rv; if ((rv = pthread_mutex_lock(&m->mx)) != 0) { nni_panic("pthread_mutex_lock failed: %s", strerror(rv)); } } void nni_mutex_exit(nni_mutex *m) { if (pthread_mutex_unlock(&m->mx) != 0) { nni_panic("pthread_mutex_unlock failed"); } } int nni_mutex_tryenter(nni_mutex *m) { if (pthread_mutex_trylock(&m->mx) != 0) { return (NNG_EBUSY); } return (0); } int nni_cond_init(nni_cond *c, nni_mutex *m) { if (pthread_cond_init(&c->cv, &nni_cvattr) != 0) { // In theory could be EAGAIN, but handle like ENOMEM return (NNG_ENOMEM); } c->mx = &m->mx; return (0); } void nni_cond_fini(nni_cond *c) { if (pthread_cond_destroy(&c->cv) != 0) { nni_panic("pthread_cond_destroy failed"); } } void nni_cond_signal(nni_cond *c) { if (pthread_cond_signal(&c->cv) != 0) { nni_panic("pthread_cond_signal failed"); } } void nni_cond_broadcast(nni_cond *c) { if (pthread_cond_broadcast(&c->cv) != 0) { nni_panic("pthread_cond_broadcast failed"); } } void nni_cond_wait(nni_cond *c) { if (pthread_cond_wait(&c->cv, c->mx) != 0) { nni_panic("pthread_cond_wait failed"); } } int nni_cond_waituntil(nni_cond *c, nni_time usec) { struct timespec ts; int rv; nni_duration delta = usec - nni_clock(); if (usec != NNI_TIME_NEVER) { ts.tv_sec = usec / 1000000; ts.tv_nsec = (usec % 1000000) * 1000; rv = pthread_cond_timedwait(&c->cv, c->mx, &ts); } else { rv = pthread_cond_wait(&c->cv, c->mx); } if (rv == ETIMEDOUT) { if (nni_clock() < usec) { // This only happens if the implementation // is buggy. nni_panic("Premature wakupe!"); } return (NNG_ETIMEDOUT); } else if (rv != 0) { nni_panic("pthread_cond_timedwait returned %d", rv); } return (0); } #endif