21 #include "JackLinuxFutex.h"    22 #include "JackTools.h"    23 #include "JackConstants.h"    24 #include "JackError.h"    25 #include "promiscuous.h"    30 #include <linux/futex.h>    35 JackLinuxFutex::JackLinuxFutex() : JackSynchro(), fSharedMem(-1), fFutex(NULL), fPrivate(false)
    37     const char* promiscuous = getenv(
"JACK_PROMISCUOUS_SERVER");
    38     fPromiscuous = (promiscuous != NULL);
    39     fPromiscuousGid = jack_group2gid(promiscuous);
    42 void JackLinuxFutex::BuildName(
const char* client_name, 
const char* server_name, 
char* res, 
int size)
    44     char ext_client_name[SYNC_MAX_NAME_SIZE + 1];
    45     JackTools::RewriteName(client_name, ext_client_name);
    47         snprintf(res, size, 
"jack_sem.%s_%s", server_name, ext_client_name);
    49         snprintf(res, size, 
"jack_sem.%d_%s_%s", JackTools::GetUID(), server_name, ext_client_name);
    53 bool JackLinuxFutex::Signal()
    56         jack_error(
"JackLinuxFutex::Signal name = %s already deallocated!!", fName);
    64     if (! __sync_bool_compare_and_swap(&fFutex->futex, 0, 1))
    67         if (! fFutex->internal) 
return true;
    70     ::syscall(__NR_futex, fFutex, fFutex->internal ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1, NULL, NULL, 0);
    74 bool JackLinuxFutex::SignalAll()
    79 bool JackLinuxFutex::Wait()
    82         jack_error(
"JackLinuxFutex::Wait name = %s already deallocated!!", fName);
    86     if (fFutex->needsChange)
    88         fFutex->needsChange = 
false;
    89         fFutex->internal = !fFutex->internal;
    94         if (__sync_bool_compare_and_swap(&fFutex->futex, 1, 0))
    97         if (::syscall(__NR_futex, fFutex, fFutex->internal ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT, 0, NULL, NULL, 0) != 0 && errno != EWOULDBLOCK)
   102 bool JackLinuxFutex::TimedWait(
long usec)
   105         jack_error(
"JackLinuxFutex::TimedWait name = %s already deallocated!!", fName);
   109     if (fFutex->needsChange)
   111         fFutex->needsChange = 
false;
   112         fFutex->internal = !fFutex->internal;
   115     const uint secs  =  usec / 1000000;
   116     const int  nsecs = (usec % 1000000) * 1000;
   118     const timespec timeout = { static_cast<time_t>(secs), nsecs };
   122         if (__sync_bool_compare_and_swap(&fFutex->futex, 1, 0))
   125         if (::syscall(__NR_futex, fFutex, fFutex->internal ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT, 0, &timeout, NULL, 0) != 0 && errno != EWOULDBLOCK)
   131 bool JackLinuxFutex::Allocate(
const char* name, 
const char* server_name, 
int value, 
bool internal)
   133     BuildName(name, server_name, fName, 
sizeof(fName));
   134     jack_log(
"JackLinuxFutex::Allocate name = %s val = %ld", fName, value);
   136     if ((fSharedMem = shm_open(fName, O_CREAT | O_RDWR, 0777)) < 0) {
   137         jack_error(
"Allocate: can't check in named futex name = %s err = %s", fName, strerror(errno));
   141     ftruncate(fSharedMem, 
sizeof(FutexData));
   143     if (fPromiscuous && (jack_promiscuous_perms(fSharedMem, fName, fPromiscuousGid) < 0)) {
   150     if ((fFutex = (FutexData*)mmap(NULL, 
sizeof(FutexData), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, fSharedMem, 0)) == NULL) {
   151         jack_error(
"Allocate: can't check in named futex name = %s err = %s", fName, strerror(errno));
   160     fFutex->futex = value;
   161     fFutex->internal = 
internal;
   162     fFutex->wasInternal = 
internal;
   163     fFutex->needsChange = 
false;
   164     fFutex->externalCount = 0;
   169 bool JackLinuxFutex::Connect(
const char* name, 
const char* server_name)
   171     BuildName(name, server_name, fName, 
sizeof(fName));
   172     jack_log(
"JackLinuxFutex::Connect name = %s", fName);
   176         jack_log(
"Already connected name = %s", name);
   180     if ((fSharedMem = shm_open(fName, O_RDWR, 0)) < 0) {
   181         jack_error(
"Connect: can't connect named futex name = %s err = %s", fName, strerror(errno));
   185     if ((fFutex = (FutexData*)mmap(NULL, 
sizeof(FutexData), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, fSharedMem, 0)) == NULL) {
   186         jack_error(
"Connect: can't connect named futex name = %s err = %s", fName, strerror(errno));
   192     if (! fPrivate && fFutex->wasInternal)
   194         const char* externalSync = getenv(
"JACK_INTERNAL_CLIENT_SYNC");
   196         if (externalSync != NULL && strstr(fName, externalSync) != NULL && ++fFutex->externalCount == 1)
   198             jack_error(
"Note: client %s running as external client temporarily", fName);
   199             fFutex->needsChange = 
true;
   206 bool JackLinuxFutex::ConnectInput(
const char* name, 
const char* server_name)
   208     return Connect(name, server_name);
   211 bool JackLinuxFutex::ConnectOutput(
const char* name, 
const char* server_name)
   213     return Connect(name, server_name);
   216 bool JackLinuxFutex::Disconnect()
   222     if (! fPrivate && fFutex->wasInternal)
   224         const char* externalSync = getenv(
"JACK_INTERNAL_CLIENT_SYNC");
   226         if (externalSync != NULL && strstr(fName, externalSync) != NULL && --fFutex->externalCount == 0)
   228             jack_error(
"Note: client %s now running as internal client again", fName);
   229             fFutex->needsChange = 
true;
   233     munmap(fFutex, 
sizeof(FutexData));
   242 void JackLinuxFutex::Destroy()
   248     munmap(fFutex, 
sizeof(FutexData));
 SERVER_EXPORT void jack_error(const char *fmt,...)
SERVER_EXPORT void jack_log(const char *fmt,...)