mirror of
https://github.com/termux/termux-packages.git
synced 2024-11-27 06:18:57 +00:00
240 lines
8.5 KiB
Diff
240 lines
8.5 KiB
Diff
The whole sense of using semaphores here is to make sure there is only one instance running
|
|
Can be implemented using lock file
|
|
+++ ./src/AudacityApp.cpp
|
|
@@ -2094,10 +2094,7 @@
|
|
#endif
|
|
|
|
#if defined(__UNIX__)
|
|
-
|
|
-#include <sys/ipc.h>
|
|
-#include <sys/sem.h>
|
|
-#include <sys/shm.h>
|
|
+#include <fcntl.h>
|
|
|
|
// Return true if there are no other instances of Audacity running,
|
|
// false otherwise.
|
|
@@ -2110,127 +2107,51 @@
|
|
wxIPV4address addr;
|
|
addr.LocalHost();
|
|
|
|
- struct sembuf op = {};
|
|
-
|
|
- // Generate the IPC key we'll use for both shared memory and semaphores.
|
|
- wxString datadir = FileNames::DataDir();
|
|
- key_t memkey = ftok(datadir.c_str(), 0);
|
|
- key_t servkey = ftok(datadir.c_str(), 1);
|
|
- key_t lockkey = ftok(datadir.c_str(), 2);
|
|
+ wxString lockPath = "@TERMUX_PREFIX@/tmp/audacity.lock";
|
|
|
|
- // Create and map the shared memory segment where the port number
|
|
+ int lockFd = -1;
|
|
+ uint16_t portnum;
|
|
+
|
|
+ // Create the file with 0666 permissions where the port number
|
|
// will be stored.
|
|
- int memid = shmget(memkey, sizeof(int), IPC_CREAT | S_IRUSR | S_IWUSR);
|
|
- if (memid == -1)
|
|
- {
|
|
- AudacityMessageBox(
|
|
- XO("Unable to create shared memory segment.\n\n"
|
|
- "error code=%d : \"%s\".").Format(errno, strerror(errno)),
|
|
- XO("Audacity Startup Failure"),
|
|
- wxOK | wxICON_ERROR);
|
|
-
|
|
+ lockFd = open(lockPath, O_RDWR | O_CREAT, 0666);
|
|
+ if (lockFd == -1) {
|
|
+ dprintf(2, "Unable to create shared memory segment. Error code=%d : \"%s\".", errno, strerror(errno));
|
|
return false;
|
|
}
|
|
|
|
- int *portnum = (int *) shmat(memid, nullptr, 0);
|
|
-
|
|
- // Create (or return) the SERVER semaphore ID
|
|
- int servid = semget(servkey, 1, IPC_CREAT | S_IRUSR | S_IWUSR);
|
|
-
|
|
- // Create the LOCK semaphore only if it doesn't already exist.
|
|
- int lockid = semget(lockkey, 1, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
|
|
-
|
|
- // If the LOCK semaphore was successfully created, then this is the first
|
|
- // time Audacity has been run during this boot of the system. In this
|
|
- // case we know we'll become the "server" application, so set up the
|
|
- // semaphores to prepare for it.
|
|
- if (lockid != -1)
|
|
- {
|
|
- // Initialize value of each semaphore, 1 indicates released and 0
|
|
- // indicates acquired.
|
|
- //
|
|
- // Note that this action is NOT recorded in the semaphore's
|
|
- // UNDO buffer.
|
|
- semctl(servid, 0, SETVAL, 1);
|
|
- semctl(lockid, 0, SETVAL, 1);
|
|
-
|
|
- // Now acquire them so the semaphores will be set to the
|
|
- // released state when the process terminates.
|
|
- op.sem_num = 0;
|
|
- op.sem_op = -1;
|
|
- op.sem_flg = SEM_UNDO;
|
|
- if (semop(lockid, &op, 1) == -1 || semop(servid, &op, 1) == -1)
|
|
- {
|
|
- AudacityMessageBox(
|
|
- XO("Unable to acquire semaphores.\n\n"
|
|
- "This is likely due to a resource shortage\n"
|
|
- "and a reboot may be required."),
|
|
- XO("Audacity Startup Failure"),
|
|
- wxOK | wxICON_ERROR);
|
|
-
|
|
- return false;
|
|
- }
|
|
-
|
|
- // We will be the server...
|
|
- isServer = true;
|
|
- }
|
|
- // Something catastrophic must have happened, so bail.
|
|
- else if (errno != EEXIST)
|
|
- {
|
|
- AudacityMessageBox(
|
|
- XO("Unable to create semaphores.\n\n"
|
|
- "This is likely due to a resource shortage\n"
|
|
- "and a reboot may be required."),
|
|
- XO("Audacity Startup Failure"),
|
|
- wxOK | wxICON_ERROR);
|
|
-
|
|
+ // Resize the file to 2 bytes
|
|
+ if (ftruncate(lockFd, 2) == -1) {
|
|
+ dprintf(2, "Unable to truncate shared memory segment. Error code=%d : \"%s\".", errno, strerror(errno));
|
|
+ close(lockFd);
|
|
return false;
|
|
}
|
|
- // Otherwise it's a normal startup and we need to determine whether
|
|
- // we'll be the server or the client.
|
|
- else
|
|
+
|
|
+ // Let's assume first byte holds SERVER lock and the second one holds CLIENT lock.
|
|
{
|
|
- // Retrieve the LOCK semaphore since we wouldn't have gotten it above.
|
|
- lockid = semget(lockkey, 1, 0);
|
|
-
|
|
- // Acquire the LOCK semaphore. We may block here if another
|
|
- // process is currently setting up the server.
|
|
- op.sem_num = 0;
|
|
- op.sem_op = -1;
|
|
- op.sem_flg = SEM_UNDO;
|
|
- if (semop(lockid, &op, 1) == -1)
|
|
- {
|
|
- AudacityMessageBox(
|
|
- XO("Unable to acquire lock semaphore.\n\n"
|
|
- "This is likely due to a resource shortage\n"
|
|
- "and a reboot may be required."),
|
|
- XO("Audacity Startup Failure"),
|
|
- wxOK | wxICON_ERROR);
|
|
-
|
|
+ struct flock client = { .l_type = F_WRLCK, .l_whence = SEEK_SET, .l_start = 1, .l_len = 1 };
|
|
+ // CLIENT lock so we should wait until it unlocks.
|
|
+ if (fcntl(lockFd, F_SETLKW, &client) == -1) {
|
|
+ dprintf(2, "Failed to obtain CLIENT lock. Error code=%d : \"%s\".", errno, strerror(errno));
|
|
+ close(lockFd);
|
|
return false;
|
|
}
|
|
+ }
|
|
|
|
- // Try to acquire the SERVER semaphore. If it's not currently active, then
|
|
- // we will become the server. Otherwise, this will fail and we'll know that
|
|
- // the server is already active and we will become the client.
|
|
- op.sem_num = 0;
|
|
- op.sem_op = -1;
|
|
- op.sem_flg = IPC_NOWAIT | SEM_UNDO;
|
|
- if (semop(servid, &op, 1) == 0)
|
|
- {
|
|
+ {
|
|
+ struct flock server = { .l_type = F_WRLCK, .l_whence = SEEK_SET, .l_start = 0, .l_len = 1 };
|
|
+ // SERVER lock, we only check if there is other server available.
|
|
+ if (fcntl(lockFd, F_SETLK, &server) == -1) {
|
|
+ if (errno == EAGAIN || errno == EACCES)
|
|
+ // Other process alredy set the lock.
|
|
+ isServer = false;
|
|
+ else {
|
|
+ dprintf(2, "Failed to obtain SERVER lock. Error code=%d : \"%s\".", errno, strerror(errno));
|
|
+ close(lockFd);
|
|
+ return false;
|
|
+ }
|
|
+ } else
|
|
isServer = true;
|
|
- }
|
|
- else if (errno != EAGAIN)
|
|
- {
|
|
- AudacityMessageBox(
|
|
- XO("Unable to acquire server semaphore.\n\n"
|
|
- "This is likely due to a resource shortage\n"
|
|
- "and a reboot may be required."),
|
|
- XO("Audacity Startup Failure"),
|
|
- wxOK | wxICON_ERROR);
|
|
-
|
|
- return false;
|
|
- }
|
|
}
|
|
|
|
// Initialize the socket server if we're to be the server.
|
|
@@ -2251,16 +2172,25 @@
|
|
// Save the port number in shared memory so that clients
|
|
// know where to connect.
|
|
mIPCServ->GetLocal(addr);
|
|
- *portnum = addr.Service();
|
|
+ portnum = addr.Service();
|
|
+ lseek(lockFd, 0, SEEK_SET);
|
|
+ if (write(lockFd, &portnum, 2) != 2) {
|
|
+ dprintf(2, "Failed to write portnum. Error code=%d : \"%s\".", errno, strerror(errno));
|
|
+ close(lockFd);
|
|
+ return false;
|
|
+ }
|
|
}
|
|
|
|
- // Now that the server is active, we release the LOCK semaphore
|
|
- // to allow any waiters to continue. The SERVER semaphore will
|
|
+ // Now that the server is active, we release the CLIENT lock
|
|
+ // to allow any waiters to continue. The SERVER lock will
|
|
// remain locked for the duration of this processes execution
|
|
// and will be cleaned up by the system.
|
|
- op.sem_num = 0;
|
|
- op.sem_op = 1;
|
|
- semop(lockid, &op, 1);
|
|
+ struct flock client = { .l_type = F_UNLCK, .l_whence = SEEK_SET, .l_start = 1, .l_len = 1 };
|
|
+ if (fcntl(lockFd, F_SETLK, &client) == -1) {
|
|
+ dprintf(2, "Failed to release CLIENT lock. Error code=%d : \"%s\".", errno, strerror(errno));
|
|
+ close(lockFd);
|
|
+ return false;
|
|
+ }
|
|
|
|
// Bail if the server creation failed.
|
|
if (mIPCServ == nullptr)
|
|
@@ -2281,12 +2211,25 @@
|
|
}
|
|
|
|
// Retrieve the port number that the server is listening on.
|
|
- addr.Service(*portnum);
|
|
+ lseek(lockFd, 0, SEEK_SET);
|
|
+ if (read(lockFd, &portnum, 2) != 2) {
|
|
+ AudacityMessageBox(
|
|
+ XO("Failed to read portnum.\n\n"
|
|
+ "error code=%d : \"%s\".").Format(errno, strerror(errno)),
|
|
+ XO("Audacity Startup Failure"),
|
|
+ wxOK | wxICON_ERROR);
|
|
+ close(lockFd);
|
|
+ return 1;
|
|
+ }
|
|
+ addr.Service(portnum);
|
|
|
|
- // Now release the LOCK semaphore.
|
|
- op.sem_num = 0;
|
|
- op.sem_op = 1;
|
|
- semop(lockid, &op, 1);
|
|
+ // Now release the CLIENT lock.
|
|
+ struct flock client = { .l_type = F_UNLCK, .l_whence = SEEK_SET, .l_start = 1, .l_len = 1 };
|
|
+ if (fcntl(lockFd, F_SETLK, &client) == -1) {
|
|
+ dprintf(2, "Failed to release CLIENT lock. Error code=%d : \"%s\".", errno, strerror(errno));
|
|
+ close(lockFd);
|
|
+ return false;
|
|
+ }
|
|
|
|
// If we get here, then Audacity is currently active. So, we connect
|
|
// to it and we forward all filenames listed on the command line to
|