1 /* $Header: /home/cvs/wavplay/locks.c,v 1.2 1999/12/04 00:01:20 wwg Exp $
2 * Warren W. Gay VE3WWG Sat May 11 15:01:58 1996
3 *
4 * MANAGE LOCKS ON THE AUDIO DEVICE:
5 *
6 * X LessTif WAV Play :
7 *
8 * Copyright (C) 1997 Warren W. Gay VE3WWG
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation version 2 of the License.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
17 * Public License for more details (see enclosed file COPYING).
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 * Send correspondance to:
24 *
25 * Warren W. Gay VE3WWG
26 *
27 * Email:
28 * ve3wwg@yahoo.com
29 * wgay@mackenziefinancial.com
30 *
31 * $Log: locks.c,v $
32 * Revision 1.2 1999/12/04 00:01:20 wwg
33 * Implement wavplay-1.4 release changes
34 *
35 * Revision 1.1.1.1 1999/11/21 19:50:56 wwg
36 * Import wavplay-1.3 into CVS
37 *
38 * Revision 1.1 1997/04/14 00:19:33 wwg
39 * Initial revision
40 *
41 */
42 static const char rcsid[] = "@(#)locks.c $Revision: 1.2 $";
43
44 #include <stdio.h>
45 #include <stdarg.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <signal.h>
49 #include <errno.h>
50 #include <unistd.h>
51 #include <sys/types.h>
52 #include <sys/ipc.h>
53 #include <sys/sem.h>
54 #include "wavplay.h"
55
56 static int SemUndo = SEM_UNDO;
57 static ErrFunc v_erf; /* Error reporting function */
58 static int bTimedOut = 0; /* True if SIGALRM is raised */
59
60 /*
61 * SIGALRM catcher:
62 */
63 static void
catch_sigalrm(int signo)64 catch_sigalrm(int signo) {
65 bTimedOut = 1; /* Mark as timed out */
66 }
67
68 /*
69 * Error reporting function for this source module:
70 */
71 static void
err(const char * format,...)72 err(const char *format,...) {
73 va_list ap;
74
75 if ( v_erf == NULL )
76 return; /* Only report error if we have function */
77 va_start(ap,format);
78 v_erf(format,ap); /* Use caller's supplied function */
79 va_end(ap);
80 }
81
82 /*
83 * OpenDSPLocks opens the existing set of 2 semaphores, or creates
84 * and initializes the new set if it does not yet exist. This
85 * program chooses not to release the IPC resource upon
86 * termination, since the semphore creation and initialization is
87 * not an atomic operation, and can be prone to failure. However,
88 * it the IPC resource is removed by some other means (like ipcrm
89 * command), this function call will create a new set using the
90 * supplied IPC Key 'LockIPCKey'.
91 *
92 * NOTES:
93 *
94 * Two semphores are created in this set. Semaphore # 0 is intended
95 * to be used as a /dev/dsp 'input lock' (play lock), and semaphore
96 * # 1 is the /dev/dsp 'output lock' (record lock). I doubt if the
97 * record lock is very useful, but there might be situations where
98 * it is needed.
99 *
100 * Class F Reporting:
101 */
102 int
OpenDSPLocks(key_t LockIPCKey,int SemUndoFlag,ErrFunc erf)103 OpenDSPLocks(key_t LockIPCKey,int SemUndoFlag,ErrFunc erf) {
104 int ipc;
105 int s;
106 int e;
107 int safety = 3;
108 union semun u;
109 static ushort init_sems[2] = { 1, 1 };
110
111 v_erf = erf; /* Set error reporting function */
112
113 /*
114 * Set the SEM_UNDO status :
115 */
116 SemUndo = SemUndoFlag ? SEM_UNDO : 0;
117
118 /*
119 * If semaphore already exists, just use it :
120 */
121 while ( (ipc = semget(LockIPCKey,2,0666)) < 0 && --safety >= 0 ) {
122
123 /*
124 * Failed to find it, try creating it :
125 */
126 if ( (ipc = semget(LockIPCKey,2,IPC_CREAT|IPC_EXCL|0666)) < 0 && errno != EEXIST ) {
127 err("Unable to create a semaphore set for key 0x%lX",
128 sys_errlist[errno],
129 LockIPCKey);
130 return -1; /* No system IPC resources? */
131 }
132
133 /*
134 * Set already exists- timing error? Try again.
135 */
136 if ( ipc < 0 ) {
137 sleep(1); /* Allow creator time to init sems */
138 continue; /* Try again */
139 }
140
141 /*
142 * We created the semaphore set - initialize so that
143 * each semaphore has the value 1 :
144 */
145 u.array = &init_sems[0];
146
147 if ( (s = semctl(ipc,0,SETALL,u)) < 0 && errno == EIDRM ) {
148 /*
149 * Another process removed our ipc resource :
150 */
151 continue; /* Try again */
152 }
153
154 if ( s < 0 ) {
155 /*
156 * We failed to initialize!
157 */
158 e = errno; /* Save error */
159 semctl(ipc,0,IPC_RMID,NULL); /* Destroy bad sems */
160 err("%s: Unable to initialize semaphore set values",sys_errlist[errno=e]);
161 return -1; /* Return err ind. */
162 }
163 }
164
165 return ipc; /* Return existing, or newly initialized sems */
166 }
167
168 /*
169 * Lock the /dev/dsp device :
170 *
171 * playrecx :
172 * 0 play lock
173 * 1 record lock
174 */
175 int
LockDSP(int ipc,int playrecx,ErrFunc erf,unsigned timeout_secs)176 LockDSP(int ipc,int playrecx,ErrFunc erf,unsigned timeout_secs) {
177 int s;
178 int e;
179 static struct sembuf sops[1] = { { 0, -1, SEM_UNDO } };
180
181 v_erf = erf; /* Set error reporting function */
182
183 sops[0].sem_num = playrecx;
184 sops[0].sem_flg = SemUndo;
185
186 bTimedOut = 0; /* Reset the timeout flag */
187
188 if ( timeout_secs > 0 ) {
189 signal(SIGALRM,catch_sigalrm); /* Prepare to catch SIGALRM */
190 alarm(timeout_secs); /* Start the timer */
191 }
192
193 while ( (s = semop(ipc,sops,1)) < 0 && errno == EINTR )
194 if ( bTimedOut ) {
195 err("Timed out: locking the %s semaphore",playrecx?"Record":"Play");
196 errno = EAGAIN; /* Mark as timed out */
197 s = -1;
198 goto xit;
199 }
200
201 if ( s < 0 )
202 err("%s: Locking the %s semaphore",sys_errlist[errno],playrecx?"Record":"Play");
203
204 /*
205 * Exit this procedure:
206 */
207 xit: e = errno; /* Preserve errno for this exit */
208 alarm(0);
209 signal(SIGALRM,SIG_DFL);
210 errno = e; /* Restore errno */
211 return s;
212 }
213
214 /*
215 * Lock the /dev/dsp device :
216 *
217 * playrecx :
218 * 0 play lock
219 * 1 record lock
220 */
221 int
UnlockDSP(int ipc,int playrecx,ErrFunc erf)222 UnlockDSP(int ipc,int playrecx,ErrFunc erf) {
223 int s;
224 static struct sembuf sops[1] = { { 0, +1, SEM_UNDO } };
225
226 v_erf = erf; /* Set error reporting function */
227
228 sops[0].sem_num = playrecx;
229 sops[0].sem_flg = SemUndo;
230
231 while ( (s = semop(ipc,sops,1)) < 0 && errno == EINTR ) ;
232
233 if ( s < 0 )
234 err("%s: Unlocking the %s semaphore",
235 sys_errlist[errno],
236 playrecx?"Record":"Play");
237
238 return s;
239 }
240
241 /* $Source: /home/cvs/wavplay/locks.c,v $ */
242