libassa 3.5.1
Loading...
Searching...
No Matches
Semaphore.cpp
Go to the documentation of this file.
1// -*- c++ -*-
2//------------------------------------------------------------------------------
3// $Id: Semaphore.cpp,v 1.5 2012/05/20 04:12:18 vlg Exp $
4//------------------------------------------------------------------------------
5// Semaphore.C
6//------------------------------------------------------------------------------
7// Copyright (c) 2000 by Vladislav Grinchenko
8//
9// This library is free software; you can redistribute it and/or
10// modify it under the terms of the GNU Library General Public
11// License as published by the Free Software Foundation; either
12// version 2 of the License, or (at your option) any later version.
13//------------------------------------------------------------------------------
14// Created: 07/10/2000
15//------------------------------------------------------------------------------
16
17#if !defined(WIN32)
18
19#include <sstream>
20#include <string>
21#include <iomanip>
22
23#include "assa/Semaphore.h"
24
25using namespace ASSA;
26
27/*--- Static definitions and constants ---*/
28
29const int ASSA::Semaphore::BIGCOUNT = 10000;
30
32{
33 {2, 0, 0}, // Wait for [2] lock to equal 0,
34 {2, 1, SEM_UNDO} // then increment [2] to 1 - this locks it.
35 // UNDO to release the lock if processes
36 // exits before explicitly unlocking.
37};
38
40{
41 {1, -1, SEM_UNDO}, // Decrement [1] (proc counter) with undo on
42 // exit,
43 {2, -1, SEM_UNDO} // then decrement [2] (lock) back to 0.
44};
45
47{
48 {1, -1, SEM_UNDO}, // Decrement [1] (proc counter) with undo on
49 // exit.
50};
51
53{
54 {2, 0, 0}, // Wait for [2] lock to equal 0,
55 {2, 1, SEM_UNDO}, // then increment [2] to 1 - this locks it,
56 {1, 1, SEM_UNDO} // then increment [1] (proc counter)
57};
58
60{
61 {2, -1, SEM_UNDO} // Decrement [2] (lock) back to 0
62};
63
65{
66 {0, 99, SEM_UNDO} // Decrement or increment [0] with undo on
67 // exit. The 99 is set to the actual amount
68 // to add or substract (positive or negative)
69};
70
71//------------------------------------------------------------------------------
72int
75{
76 trace_with_mask("Semaphore::create", SEM);
77
78 register int semval;
79
80 union semnum {
81 int val;
82 struct semid_ds* buf;
85
86 if (IPC_PRIVATE == key_) {
87 EL((ASSAERR,"Not intended for private semaphores\n"));
88 return (-1);
89 }
90 else if (key_ == (key_t) -1) {
91 EL((ASSAERR,"Probably an ftok() error by caller\n"));
92 return (-1);
93 }
94
95 m_key = key_;
96 bool done = false;
97
98 while (!done) {
99 if ( (m_id = semget (m_key, 3, 0666 | IPC_CREAT)) < 0) {
100 EL((ASSAERR,"Permission problem or kernel tables full\n"));
101 return (-1);
102 }
103 /*
104 When the semaphore is created, we know that the value of
105 all 3 set members is 0.
106
107 Get a lock on the semaphore by waiting for [2] to equal 0,
108 then increment it.
109
110 There is a race condition here. There is a possibility
111 that between the semget(2) and semop(2) below, another
112 process can cal Semaphore:::close () member function
113 which can remove a semaphore if that process is the last
114 one using it.
115
116 Therefore, we handle the error condition of an invalid
117 semaphore ID specially below, and if it does happen, we
118 just go back and create it again.
119 */
120
121 if (semop (m_id, &m_op_lock[0], 2) < 0) {
122 if (errno == EINVAL) {
123 continue;
124 }
125 EL((ASSAERR,"Can't lock semaphore\n"));
126 Assure_exit (false);
127 }
128 done = true;
129 } // while (!done)
130
131 /*
132 Get the value of the process counter. If it equals 0,
133 then no one has initialized the semaphore yet.
134 */
135 if ((semval = semctl (m_id, 1, GETVAL, 0)) < 0) {
136 EL((ASSAERR,"Can't GETVAL\n"));
137 Assure_exit (false);
138 }
139
140 if (semval == 0) {
141 /*
142 We could initalize by doing a SETALL, but that
143 would clear the adjust value that we set when
144 we locked the semaphore above. Instead, we'll do
145 two system calls to initialize semaphore value [0]
146 and process counter [1].
147 */
148 semctrl_arg.val = initval_;
149
150 if (semctl (m_id, 0, SETVAL, semctrl_arg) < 0) {
151 EL((ASSAERR,"Can't SETVAL[0]\n"));
152 Assure_exit (false);
153 }
154
155 semctrl_arg.val = BIGCOUNT;
156
157 if (semctl (m_id, 1, SETVAL, semctrl_arg) < 0) {
158 EL((ASSAERR,"Can't SETVAL[1]\n"));
159 Assure_exit (false);
160 }
161 } // if (semval == 0)
162
163 /*--- Decrement the process counter and then release the lock. ---*/
164
165 if (semop (m_id, &m_op_endcreate[0], 2) < 0) {
166 EL((ASSAERR,"Error on semop (ndcreate)\n"));
167 Assure_exit (false);
168 }
169 return (m_id);
170}
171
172int
175{
176 trace_with_mask("Semaphore::open", SEM);
177
178 if (IPC_PRIVATE == key_) {
179 EL((ASSAERR,"Not intended for private semaphores\n"));
180 return (-1);
181 }
182 else if (key_ == (key_t) -1) {
183 EL((ASSAERR,"Probably an ftok() error by caller\n"));
184 return (-1);
185 }
186
187 m_key = key_;
188
189 if ((m_id = semget (m_key, 3, 0)) < 0) {
190 EL((ASSAERR,"Error on semget(3)"));
191 return (-1);
192 }
193 /*--- Decrement the process counter. No need for lock ---*/
194
195 if (semop (m_id, &m_op_open[0], 1) < 0) {
196 EL((ASSAERR,"Error on semget(open)\n"));
197 Assure_exit(false);
198 }
199 return (m_id);
200}
201
202void
204remove ()
205{
206 trace_with_mask("Semaphore::remove", SEM);
207
208 if (m_id < 0 || m_key == ((key_t) -1) ) return;
209
210 if (semctl (m_id, 0, IPC_RMID, 0) < 0) {
211 EL((ASSAERR,"Can't IPC_RMID\n"));
212 Assure_exit(false);
213 }
214 init ();
215}
216
217void
219close ()
220{
221 trace_with_mask("Semaphore::close", SEM);
222
223 register int semval;
224
225 if (m_id < 0) return;
226
227 /*
228 First get the lock on semaphore, then increment process counter.
229 */
230 if (semop (m_id, &m_op_close[0], 3) < 0) {
231 EL((ASSAERR,"Can't semop(2)\n"));
232 Assure_exit(false);
233 }
234 /*
235 Now that we have a lock, read the value of the process counter
236 to see if this is the last reference to the semaphore.
237 There is a race condition here (same as in Semaphore::create()).
238 */
239 if ((semval = semctl (m_id, 1, GETVAL, 0)) < 0) {
240 EL((ASSAERR,"Can't GETVAL\n"));
241 Assure_exit(false);
242 }
243
244 if (semval > BIGCOUNT) {
245 EL((ASSAERR,"sem[1] > BIGCOUNT\n"));
246 Assure_exit(false);
247 }
248 else if (semval == BIGCOUNT) {
249 remove ();
250 }
251 else if (semop (m_id, &m_op_unlock[0], 1) < 0) {
252 EL((ASSAERR,"Can't unlock\n"));
253 Assure_exit(false);
254 }
255 /*--- Invalidate ---*/
256 init ();
257}
258
259
260void
262op (int value_)
263{
264 /* Test if m_id is still valid. If it fails, then
265 * next operation is failing because of it. If not,
266 * then something else happens here.
267 */
268 trace_with_mask("Semaphore::op", SEM);
269
270 int semval = 0;
271 dump ();
272
273 if ((semval = semctl (m_id, 1, GETVAL, 0)) < 0) {
274 EL((ASSAERR,"Can't GETVAL\n"));
275 Assure_exit (false);
276 }
277
278 /* This will fail on Solaris? */
279
280 if ((m_op_op[0].sem_op = value_) == 0) {
281 EL((ASSAERR,"Can't have value_ == 0\n"));
282 Assure_exit(false);
283 }
284
285 if (semop (m_id, &m_op_op[0], 1) < 0) {
286 EL((ASSAERR,"sem_op error\n"));
287 Assure_exit(false);
288 }
289}
290
291void
293dump (void) const
294{
295 trace_with_mask("Semaphore::dump", SEM);
296
297 std::ostringstream msg;
298 msg << "\n\n\tKey.....: ";
299
300 if (m_key == (key_t) -1) {
301 msg << m_key;
302 }
303 else {
304 msg << "0x" << std::hex << m_key << std::dec;
305 }
306
307 msg << "\n\tID......: " << m_id << "\n\n";
308
309 if (m_id >= 0 && m_key >= (key_t) -1) {
310 msg << "\tsemval [0]\tproc counter[1]\tlock [2]\n"
311 << "\t----------\t---------------\t--------\n";
312
313 /*--- Get value of element in semaphore set ---*/
314 msg << "\t " << semctl (m_id, 0, GETVAL)
315 << "\t\t " << semctl (m_id, 1, GETVAL)
316 << "\t\t " << semctl (m_id, 2, GETVAL);
317 }
318 else {
319 msg << "Semaphore id = -1. No info is available.";
320 }
321 msg << std::ends;
322 DL((SEM,"%s\n\n", msg.str ().c_str ()));
323}
324
325#endif /* !defined(WIN32) */
326
#define Assure_exit(exp_)
Macro that makes program exit if assert fails.
Definition Assure.h:39
#define EL(X)
A macro for writing error message to the Logger.
Definition Logger.h:285
#define DL(X)
A macro for writing debug message to the Logger.
Definition Logger.h:273
#define trace_with_mask(s, m)
trace_with_mask() is used to trace function call chain in C++ program.
Definition Logger.h:437
Semaphore class provides a simpler and easier interface to System V semaphore system calls.
A wrapper class to provide AutoPtr with reference semantics.
Definition AutoPtr.h:32
static sembuf m_op_open[2]
Decrement process counter with undo on exit.
Definition Semaphore.h:171
int m_id
Semaphore's id.
Definition Semaphore.h:154
void remove()
Remove a semaphore.
int create(key_t key_, int initval_=1)
Create a semaphore with a specified initial value.
Definition Semaphore.cpp:74
void init()
Initalize by invalidating data members.
Definition Semaphore.h:211
static sembuf m_op_op[1]
Decrement or increment semaphore with undo on exit.
Definition Semaphore.h:186
static sembuf m_op_unlock[1]
Decremetn lock back to 0.
Definition Semaphore.h:180
static sembuf m_op_close[3]
Wait for lock to equal 0, then increment lock to 1 (lock it), then increment process counter.
Definition Semaphore.h:176
key_t m_key
Semaphore's key.
Definition Semaphore.h:151
void op(int val_)
General semaphore operation.
static sembuf m_op_lock[2]
Wait for lock to equal 0, then increment lock to 1 - this locks it.
Definition Semaphore.h:161
static const int BIGCOUNT
Definition Semaphore.h:157
void dump(void) const
Dump the objects state along with the state of the semaphore (if connected) to the log file.
static sembuf m_op_endcreate[2]
Decrement process counter with undo on exit, then decrement lock back to 0.
Definition Semaphore.h:166
void close()
Close a semaphore.
int open(key_t key_)
Open a semaphore that must already exist.
@ SEM
Class Semaphore messages
Definition LogMask.h:37
@ ASSAERR
ASSA and system errors
Definition LogMask.h:34