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 FutexData* futex = (FutexData*)mmap(NULL,
sizeof(FutexData), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, fSharedMem, 0);
152 if (futex == NULL || futex == MAP_FAILED) {
153 jack_error(
"Allocate: can't check in named futex name = %s err = %s", fName, strerror(errno));
162 futex->futex = value;
163 futex->internal =
internal;
164 futex->wasInternal =
internal;
165 futex->needsChange =
false;
166 futex->externalCount = 0;
172 bool JackLinuxFutex::Connect(
const char* name,
const char* server_name)
174 BuildName(name, server_name, fName,
sizeof(fName));
175 jack_log(
"JackLinuxFutex::Connect name = %s", fName);
179 jack_log(
"Already connected name = %s", name);
183 if ((fSharedMem = shm_open(fName, O_RDWR, 0)) < 0) {
184 jack_error(
"Connect: can't connect named futex name = %s err = %s", fName, strerror(errno));
188 FutexData* futex = (FutexData*)mmap(NULL,
sizeof(FutexData), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, fSharedMem, 0);
190 if (futex == NULL || futex == MAP_FAILED) {
191 jack_error(
"Connect: can't connect named futex name = %s err = %s", fName, strerror(errno));
197 if (! fPrivate && futex->wasInternal)
199 const char* externalSync = getenv(
"JACK_INTERNAL_CLIENT_SYNC");
201 if (externalSync != NULL && strstr(fName, externalSync) != NULL && ++futex->externalCount == 1)
203 jack_error(
"Note: client %s running as external client temporarily", fName);
204 futex->needsChange =
true;
212 bool JackLinuxFutex::ConnectInput(
const char* name,
const char* server_name)
214 return Connect(name, server_name);
217 bool JackLinuxFutex::ConnectOutput(
const char* name,
const char* server_name)
219 return Connect(name, server_name);
222 bool JackLinuxFutex::Disconnect()
228 if (! fPrivate && fFutex->wasInternal)
230 const char* externalSync = getenv(
"JACK_INTERNAL_CLIENT_SYNC");
232 if (externalSync != NULL && strstr(fName, externalSync) != NULL && --fFutex->externalCount == 0)
234 jack_error(
"Note: client %s now running as internal client again", fName);
235 fFutex->needsChange =
true;
239 munmap(fFutex,
sizeof(FutexData));
248 void JackLinuxFutex::Destroy()
254 munmap(fFutex,
sizeof(FutexData));
SERVER_EXPORT void jack_error(const char *fmt,...)
SERVER_EXPORT void jack_log(const char *fmt,...)