summaryrefslogtreecommitdiff
path: root/linux
diff options
context:
space:
mode:
authorAdrian Knoth <adi@drcomp.erfurt.thur.de>2017-03-12 20:53:13 +0100
committerGitHub <noreply@github.com>2017-03-12 20:53:13 +0100
commit701f74fa2059621effd6a1a904198fca28f8aabe (patch)
tree149b51e228399f012132a2ccdc05cc3f8c628287 /linux
parent179b976fdd50f40d2eaf1ba4fb6bf8f101b5af1c (diff)
parent112b6bdf39be3afb0a3af9e2bbdd5bb94525466f (diff)
downloadjack2-701f74fa2059621effd6a1a904198fca28f8aabe.tar.gz
Merge pull request #219 from falkTX/master
Use linux futex as JackSynchro
Diffstat (limited to 'linux')
-rw-r--r--linux/JackLinuxFutex.cpp243
-rw-r--r--linux/JackLinuxFutex.h85
-rw-r--r--linux/JackPlatformPlug_os.h4
3 files changed, 330 insertions, 2 deletions
diff --git a/linux/JackLinuxFutex.cpp b/linux/JackLinuxFutex.cpp
new file mode 100644
index 00000000..6e897bc8
--- /dev/null
+++ b/linux/JackLinuxFutex.cpp
@@ -0,0 +1,243 @@
+/*
+Copyright (C) 2004-2008 Grame
+Copyright (C) 2016 Filipe Coelho
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "JackLinuxFutex.h"
+#include "JackTools.h"
+#include "JackConstants.h"
+#include "JackError.h"
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <syscall.h>
+#include <linux/futex.h>
+
+namespace Jack
+{
+
+void JackLinuxFutex::BuildName(const char* client_name, const char* server_name, char* res, int size)
+{
+ char ext_client_name[SYNC_MAX_NAME_SIZE + 1];
+ JackTools::RewriteName(client_name, ext_client_name);
+ if (getenv("JACK_PROMISCUOUS_SERVER")) {
+ snprintf(res, size, "jack_sem.%s_%s", server_name, ext_client_name);
+ } else {
+ snprintf(res, size, "jack_sem.%d_%s_%s", JackTools::GetUID(), server_name, ext_client_name);
+ }
+}
+
+bool JackLinuxFutex::Signal()
+{
+ if (!fFutex) {
+ jack_error("JackLinuxFutex::Signal name = %s already deallocated!!", fName);
+ return false;
+ }
+
+ if (fFlush) {
+ return true;
+ }
+
+ if (! __sync_bool_compare_and_swap(&fFutex->futex, 0, 1))
+ {
+ // already unlocked, do not wake futex
+ if (! fFutex->internal) return true;
+ }
+
+ ::syscall(__NR_futex, fFutex, fFutex->internal ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1, NULL, NULL, 0);
+ return true;
+}
+
+bool JackLinuxFutex::SignalAll()
+{
+ return Signal();
+}
+
+bool JackLinuxFutex::Wait()
+{
+ if (!fFutex) {
+ jack_error("JackLinuxFutex::Wait name = %s already deallocated!!", fName);
+ return false;
+ }
+
+ if (fFutex->needsChange)
+ {
+ fFutex->needsChange = false;
+ fFutex->internal = !fFutex->internal;
+ }
+
+ for (;;)
+ {
+ if (__sync_bool_compare_and_swap(&fFutex->futex, 1, 0))
+ return true;
+
+ if (::syscall(__NR_futex, fFutex, fFutex->internal ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT, 0, NULL, NULL, 0) != 0 && errno != EWOULDBLOCK)
+ return false;
+ }
+}
+
+bool JackLinuxFutex::TimedWait(long usec)
+{
+ if (!fFutex) {
+ jack_error("JackLinuxFutex::TimedWait name = %s already deallocated!!", fName);
+ return false;
+ }
+
+ if (fFutex->needsChange)
+ {
+ fFutex->needsChange = false;
+ fFutex->internal = !fFutex->internal;
+ }
+
+ const uint secs = usec / 1000000;
+ const int nsecs = (usec % 1000000) * 1000;
+
+ const timespec timeout = { static_cast<time_t>(secs), nsecs };
+
+ for (;;)
+ {
+ if (__sync_bool_compare_and_swap(&fFutex->futex, 1, 0))
+ return true;
+
+ if (::syscall(__NR_futex, fFutex, fFutex->internal ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT, 0, &timeout, NULL, 0) != 0 && errno != EWOULDBLOCK)
+ return false;
+ }
+}
+
+// Server side : publish the futex in the global namespace
+bool JackLinuxFutex::Allocate(const char* name, const char* server_name, int value, bool internal)
+{
+ BuildName(name, server_name, fName, sizeof(fName));
+ jack_log("JackLinuxFutex::Allocate name = %s val = %ld", fName, value);
+
+ if ((fSharedMem = shm_open(fName, O_CREAT | O_RDWR, 0777)) < 0) {
+ jack_error("Allocate: can't check in named futex name = %s err = %s", fName, strerror(errno));
+ return false;
+ }
+
+ ftruncate(fSharedMem, sizeof(FutexData));
+
+ if ((fFutex = (FutexData*)mmap(NULL, sizeof(FutexData), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, fSharedMem, 0)) == NULL) {
+ jack_error("Allocate: can't check in named futex name = %s err = %s", fName, strerror(errno));
+ close(fSharedMem);
+ fSharedMem = -1;
+ shm_unlink(fName);
+ return false;
+ }
+
+ fPrivate = internal;
+
+ fFutex->futex = value;
+ fFutex->internal = internal;
+ fFutex->wasInternal = internal;
+ fFutex->needsChange = false;
+ fFutex->externalCount = 0;
+ return true;
+}
+
+// Client side : get the published futex from server
+bool JackLinuxFutex::Connect(const char* name, const char* server_name)
+{
+ BuildName(name, server_name, fName, sizeof(fName));
+ jack_log("JackLinuxFutex::Connect name = %s", fName);
+
+ // Temporary...
+ if (fFutex) {
+ jack_log("Already connected name = %s", name);
+ return true;
+ }
+
+ if ((fSharedMem = shm_open(fName, O_RDWR, 0)) < 0) {
+ jack_error("Connect: can't connect named futex name = %s err = %s", fName, strerror(errno));
+ return false;
+ }
+
+ if ((fFutex = (FutexData*)mmap(NULL, sizeof(FutexData), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, fSharedMem, 0)) == NULL) {
+ jack_error("Connect: can't connect named futex name = %s err = %s", fName, strerror(errno));
+ close(fSharedMem);
+ fSharedMem = -1;
+ return false;
+ }
+
+ if (! fPrivate && fFutex->wasInternal)
+ {
+ const char* externalSync = getenv("JACK_INTERNAL_CLIENT_SYNC");
+
+ if (externalSync != NULL && strstr(fName, externalSync) != NULL && ++fFutex->externalCount == 1)
+ {
+ jack_error("Note: client %s running as external client temporarily", fName);
+ fFutex->needsChange = true;
+ }
+ }
+
+ return true;
+}
+
+bool JackLinuxFutex::ConnectInput(const char* name, const char* server_name)
+{
+ return Connect(name, server_name);
+}
+
+bool JackLinuxFutex::ConnectOutput(const char* name, const char* server_name)
+{
+ return Connect(name, server_name);
+}
+
+bool JackLinuxFutex::Disconnect()
+{
+ if (!fFutex) {
+ return true;
+ }
+
+ if (! fPrivate && fFutex->wasInternal)
+ {
+ const char* externalSync = getenv("JACK_INTERNAL_CLIENT_SYNC");
+
+ if (externalSync != NULL && strstr(fName, externalSync) != NULL && --fFutex->externalCount == 0)
+ {
+ jack_error("Note: client %s now running as internal client again", fName);
+ fFutex->needsChange = true;
+ }
+ }
+
+ munmap(fFutex, sizeof(FutexData));
+ fFutex = NULL;
+
+ close(fSharedMem);
+ fSharedMem = -1;
+ return true;
+}
+
+// Server side : destroy the futex
+void JackLinuxFutex::Destroy()
+{
+ if (!fFutex) {
+ return;
+ }
+
+ munmap(fFutex, sizeof(FutexData));
+ fFutex = NULL;
+
+ close(fSharedMem);
+ fSharedMem = -1;
+
+ shm_unlink(fName);
+}
+
+} // end of namespace
+
diff --git a/linux/JackLinuxFutex.h b/linux/JackLinuxFutex.h
new file mode 100644
index 00000000..5c8a7006
--- /dev/null
+++ b/linux/JackLinuxFutex.h
@@ -0,0 +1,85 @@
+/*
+Copyright (C) 2004-2008 Grame
+Copyright (C) 2016 Filipe Coelho
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#ifndef __JackLinuxFutex__
+#define __JackLinuxFutex__
+
+#include "JackSynchro.h"
+#include "JackCompilerDeps.h"
+#include <stddef.h>
+
+namespace Jack
+{
+
+/*!
+\brief Inter process synchronization using Linux futex.
+
+ Based on the JackPosixSemaphore class.
+ Adapted to work with linux futex to be as light as possible and also work in multiple architectures.
+
+ Adds a new 'MakePrivate' function that makes the sync happen in the local process only,
+ making it even faster for internal clients.
+*/
+
+class SERVER_EXPORT JackLinuxFutex : public detail::JackSynchro
+{
+
+ private:
+ struct FutexData {
+ int futex; // futex, needs to be 1st member
+ bool internal; // current internal state
+ bool wasInternal; // initial internal state, only changes in allocate
+ bool needsChange; // change state on next wait call
+ int externalCount; // how many external clients have connected
+ };
+
+ int fSharedMem;
+ FutexData* fFutex;
+ bool fPrivate;
+
+ protected:
+
+ void BuildName(const char* name, const char* server_name, char* res, int size);
+
+ public:
+
+ JackLinuxFutex():JackSynchro(), fSharedMem(-1), fFutex(NULL), fPrivate(false)
+ {}
+
+ bool Signal();
+ bool SignalAll();
+ bool Wait();
+ bool TimedWait(long usec);
+
+ bool Allocate(const char* name, const char* server_name, int value, bool internal = false);
+ bool Connect(const char* name, const char* server_name);
+ bool ConnectInput(const char* name, const char* server_name);
+ bool ConnectOutput(const char* name, const char* server_name);
+ bool Disconnect();
+ void Destroy();
+
+ void MakePrivate(bool priv);
+};
+
+} // end of namespace
+
+
+#endif
+
diff --git a/linux/JackPlatformPlug_os.h b/linux/JackPlatformPlug_os.h
index b480f453..60c9a585 100644
--- a/linux/JackPlatformPlug_os.h
+++ b/linux/JackPlatformPlug_os.h
@@ -54,8 +54,8 @@ namespace Jack { typedef JackPosixThread JackThread; }
namespace Jack { typedef JackFifo JackSynchro; }
*/
-#include "JackPosixSemaphore.h"
-namespace Jack { typedef JackPosixSemaphore JackSynchro; }
+#include "JackLinuxFutex.h"
+namespace Jack { typedef JackLinuxFutex JackSynchro; }
/* __JackPlatformChannelTransaction__ */
/*