Jack2  1.9.12
JackPosixSemaphore.cpp
1 /*
2 Copyright (C) 2004-2008 Grame
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13 
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 
18 */
19 
20 #include "JackPosixSemaphore.h"
21 #include "JackTools.h"
22 #include "JackConstants.h"
23 #include "JackError.h"
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <sys/time.h>
27 #ifdef __linux__
28 #include "promiscuous.h"
29 #endif
30 
31 namespace Jack
32 {
33 
34 JackPosixSemaphore::JackPosixSemaphore() : JackSynchro(), fSemaphore(NULL)
35 {
36  const char* promiscuous = getenv("JACK_PROMISCUOUS_SERVER");
37  fPromiscuous = (promiscuous != NULL);
38 #ifdef __linux__
39  fPromiscuousGid = jack_group2gid(promiscuous);
40 #endif
41 }
42 
43 void JackPosixSemaphore::BuildName(const char* client_name, const char* server_name, char* res, int size)
44 {
45  char ext_client_name[SYNC_MAX_NAME_SIZE + 1];
46  JackTools::RewriteName(client_name, ext_client_name);
47 #if __APPLE__ // POSIX semaphore names are limited to 32 characters...
48  snprintf(res, 32, "js_%s", ext_client_name);
49 #else
50  if (fPromiscuous) {
51  snprintf(res, size, "jack_sem.%s_%s", server_name, ext_client_name);
52  } else {
53  snprintf(res, size, "jack_sem.%d_%s_%s", JackTools::GetUID(), server_name, ext_client_name);
54  }
55 #endif
56 }
57 
58 bool JackPosixSemaphore::Signal()
59 {
60  int res;
61 
62  if (!fSemaphore) {
63  jack_error("JackPosixSemaphore::Signal name = %s already deallocated!!", fName);
64  return false;
65  }
66 
67  if (fFlush) {
68  return true;
69  }
70 
71  if ((res = sem_post(fSemaphore)) != 0) {
72  jack_error("JackPosixSemaphore::Signal name = %s err = %s", fName, strerror(errno));
73  }
74  return (res == 0);
75 }
76 
77 bool JackPosixSemaphore::SignalAll()
78 {
79  int res;
80 
81  if (!fSemaphore) {
82  jack_error("JackPosixSemaphore::SignalAll name = %s already deallocated!!", fName);
83  return false;
84  }
85 
86  if (fFlush) {
87  return true;
88  }
89 
90  if ((res = sem_post(fSemaphore)) != 0) {
91  jack_error("JackPosixSemaphore::SignalAll name = %s err = %s", fName, strerror(errno));
92  }
93  return (res == 0);
94 }
95 
96 bool JackPosixSemaphore::Wait()
97 {
98  int res;
99 
100  if (!fSemaphore) {
101  jack_error("JackPosixSemaphore::Wait name = %s already deallocated!!", fName);
102  return false;
103  }
104 
105  while ((res = sem_wait(fSemaphore) < 0)) {
106  jack_error("JackPosixSemaphore::Wait name = %s err = %s", fName, strerror(errno));
107  if (errno != EINTR) {
108  break;
109  }
110  }
111  return (res == 0);
112 }
113 
114 #if (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) // glibc feature test
115 
116 bool JackPosixSemaphore::TimedWait(long usec)
117 {
118  int res;
119  struct timeval now;
120  timespec time;
121 
122  if (!fSemaphore) {
123  jack_error("JackPosixSemaphore::TimedWait name = %s already deallocated!!", fName);
124  return false;
125  }
126  gettimeofday(&now, 0);
127  time.tv_sec = now.tv_sec + usec / 1000000;
128  long tv_usec = (now.tv_usec + (usec % 1000000));
129  time.tv_sec += tv_usec / 1000000;
130  time.tv_nsec = (tv_usec % 1000000) * 1000;
131 
132  while ((res = sem_timedwait(fSemaphore, &time)) < 0) {
133  jack_error("JackPosixSemaphore::TimedWait err = %s", strerror(errno));
134  jack_log("JackPosixSemaphore::TimedWait now : %ld %ld ", now.tv_sec, now.tv_usec);
135  jack_log("JackPosixSemaphore::TimedWait next : %ld %ld ", time.tv_sec, time.tv_nsec/1000);
136  if (errno != EINTR) {
137  break;
138  }
139  }
140  return (res == 0);
141 }
142 
143 #else
144 #warning "JackPosixSemaphore::TimedWait is not supported: Jack in SYNC mode with JackPosixSemaphore will not run properly !!"
145 
146 bool JackPosixSemaphore::TimedWait(long usec)
147 {
148  return Wait();
149 }
150 #endif
151 
152 // Server side : publish the semaphore in the global namespace
153 bool JackPosixSemaphore::Allocate(const char* name, const char* server_name, int value)
154 {
155  BuildName(name, server_name, fName, sizeof(fName));
156  jack_log("JackPosixSemaphore::Allocate name = %s val = %ld", fName, value);
157 
158  if ((fSemaphore = sem_open(fName, O_CREAT | O_RDWR, 0777, value)) == (sem_t*)SEM_FAILED) {
159  jack_error("Allocate: can't check in named semaphore name = %s err = %s", fName, strerror(errno));
160  return false;
161  } else {
162 #ifdef __linux__
163  if (fPromiscuous) {
164  char sempath[SYNC_MAX_NAME_SIZE+13];
165  snprintf(sempath, sizeof(sempath), "/dev/shm/sem.%s", fName);
166  if (jack_promiscuous_perms(-1, sempath, fPromiscuousGid) < 0)
167  return false;
168  }
169 #endif
170  return true;
171  }
172 }
173 
174 // Client side : get the published semaphore from server
175 bool JackPosixSemaphore::ConnectInput(const char* name, const char* server_name)
176 {
177  BuildName(name, server_name, fName, sizeof(fName));
178  jack_log("JackPosixSemaphore::Connect name = %s", fName);
179 
180  // Temporary...
181  if (fSemaphore) {
182  jack_log("Already connected name = %s", name);
183  return true;
184  }
185 
186  if ((fSemaphore = sem_open(fName, O_RDWR)) == (sem_t*)SEM_FAILED) {
187  jack_error("Connect: can't connect named semaphore name = %s err = %s", fName, strerror(errno));
188  return false;
189  } else if (fSemaphore) {
190  int val = 0;
191  sem_getvalue(fSemaphore, &val);
192  jack_log("JackPosixSemaphore::Connect sem_getvalue %ld", val);
193  return true;
194  } else {
195  jack_error("Connect: fSemaphore not initialized!");
196  return false;
197  }
198 }
199 
200 bool JackPosixSemaphore::Connect(const char* name, const char* server_name)
201 {
202  return ConnectInput(name, server_name);
203 }
204 
205 bool JackPosixSemaphore::ConnectOutput(const char* name, const char* server_name)
206 {
207  return ConnectInput(name, server_name);
208 }
209 
210 bool JackPosixSemaphore::Disconnect()
211 {
212  if (fSemaphore) {
213  jack_log("JackPosixSemaphore::Disconnect name = %s", fName);
214  if (sem_close(fSemaphore) != 0) {
215  jack_error("Disconnect: can't disconnect named semaphore name = %s err = %s", fName, strerror(errno));
216  return false;
217  } else {
218  fSemaphore = NULL;
219  return true;
220  }
221  } else {
222  return true;
223  }
224 }
225 
226 // Server side : destroy the semaphore
227 void JackPosixSemaphore::Destroy()
228 {
229  if (fSemaphore != NULL) {
230  jack_log("JackPosixSemaphore::Destroy name = %s", fName);
231  sem_unlink(fName);
232  if (sem_close(fSemaphore) != 0) {
233  jack_error("Destroy: can't destroy semaphore name = %s err = %s", fName, strerror(errno));
234  }
235  fSemaphore = NULL;
236  } else {
237  jack_error("JackPosixSemaphore::Destroy semaphore == NULL");
238  }
239 }
240 
241 } // end of namespace
242 
jack_log
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:108
jack_error
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92