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,...)