source: sources/src/pcSyncProcess.cc @ 1497:a2a9d4ede6bf

Revision 1497:a2a9d4ede6bf, 9.1 KB checked in by Dmytro Milinevskyy <millinevskyy@…>, 14 months ago (diff)

{issue #109[resolved]} reorganize misc:random helpers

Line 
1/***************************************************************************
2 *            pcSyncProcess.cc
3 *
4 *  Sun Jul 22 2007
5 *  Copyright  2007  Dmytro Milinevskyy
6 *  milinevskyy@gmail.com
7 ****************************************************************************/
8
9/*
10 *  This program is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU Lesser General Public License version 2.1 as published by
12 *  the Free Software Foundation;
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU Library General Public License for more details.
18 *
19 *  You should have received a copy of the GNU Lesser General Public License
20 *  along with this program; if not, write to the Free Software
21 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24/**
25 * vim indentation settings
26 * set tabstop=4
27 * set shiftwidth=4
28 */
29
30#include <libdodo/directives.h>
31
32#ifdef XSI_IPC
33#include <sys/ipc.h>
34#include <sys/sem.h>
35#else /*POSIX_LOCKS*/
36#include <fcntl.h>
37#include <semaphore.h>
38#endif
39#include <sys/stat.h>
40#include <time.h>
41#include <errno.h>
42#include <string.h>
43#include <unistd.h>
44
45#include <libdodo/pcSyncProcess.h>
46#include <libdodo/pcSyncProtector.h>
47#include <libdodo/pcSyncProcessEx.h>
48#include <libdodo/types.h>
49#include <libdodo/toolsMisc.h>
50#include <libdodo/toolsCode.h>
51
52namespace dodo {
53    namespace pc {
54        namespace sync {
55            /**
56             * @struct process::__lock__
57             * @brief defines system lock
58             */
59            struct process::__lock__ {
60                /**
61                 * constructor
62                 */
63                __lock__() :
64#ifdef XSI_IPC
65                    keeper(-1)
66#else
67                    keeper(NULL)
68#endif
69                {
70                }
71
72#ifdef XSI_IPC
73                int        keeper;              ///< lock
74                int        key;                 ///< key for the lock
75                union semun {
76                    int             val;
77                    struct semid_ds *buf;
78                    ushort          *array;
79                } control;                      ///< lock lock->control structure
80
81                sembuf     operations[1];       ///< lock lock->operations
82#else
83                sem_t      *keeper;             ///< lock
84                dodo::string key;                 ///< key for the lock
85#endif
86            };
87        };
88    };
89};
90
91using namespace dodo::pc::sync;
92
93process::process(process &)
94{
95}
96
97//-------------------------------------------------------------------
98
99process::process(int a_key) : lock(new process::__lock__),
100                              autogenerated(false),
101                              recursive(0)
102
103{
104#ifdef XSI_IPC
105    if (a_key == 0) {
106        lock->key = tools::misc::random<int>();
107
108        autogenerated = true;
109    } else {
110        lock->key = a_key;
111    }
112
113    lock->operations[0].sem_num = 0;
114    lock->operations[0].sem_flg = 0;
115
116    lock->keeper = semget(lock->key, 1, S_IRUSR | S_IWUSR | IPC_CREAT);
117    if (lock->keeper == -1) {
118        delete lock;
119
120        dodo_throw exception::basic(exception::MODULE_PCSYNCPROCESS, PROCESSEX_CONSTRUCTOR, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
121    }
122
123    lock->control.val = 1;
124
125    if (semctl(lock->keeper, 0, SETVAL, lock->control) == -1) {
126        delete lock;
127
128        dodo_throw exception::basic(exception::MODULE_PCSYNCPROCESS, PROCESSEX_CONSTRUCTOR, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
129    }
130#else
131    lock->key = '/';
132
133    if (a_key == 0) {
134        char _key[SH_KEY_SIZE / 2 - 1];
135        tools::misc::randomBlob(_key, SH_KEY_SIZE / 2 - 1);
136
137        lock->key += dodo::string(tools::code::binToHex(dodo::string(_key, SH_KEY_SIZE / 2 - 1)));
138
139        autogenerated = true;
140    } else {
141        char _key[4];
142        memcpy(_key, &a_key, 4);
143
144        lock->key += dodo::string(tools::code::binToHex(dodo::string(_key, 4)));
145    }
146
147    lock->keeper = sem_open(lock->key.data(), O_CREAT, S_IRUSR | S_IWUSR, 1);
148    if (lock->keeper == SEM_FAILED) {
149        delete lock;
150
151        dodo_throw exception::basic(exception::MODULE_PCSYNCPROCESS, PROCESSEX_CONSTRUCTOR, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
152    }
153#endif
154}
155
156//-------------------------------------------------------------------
157
158process::~process()
159{
160#ifdef XSI_IPC
161    dodo_try {
162        if (acquired() && getpid() == current) {
163            lock->operations[0].sem_op = 1;
164
165            semop(lock->keeper, lock->operations, 1);
166        }
167    } dodo_catch (exception::basic *e UNUSED) {
168    }
169
170    if (autogenerated)
171        semctl(lock->keeper, 0, IPC_RMID);
172#else
173    dodo_try {
174        if (acquired() && getpid() == current)
175            sem_post(lock->keeper);
176    } dodo_catch (exception::basic *e UNUSED) {
177    }
178
179    sem_close(lock->keeper);
180
181    if (autogenerated)
182        sem_unlink(lock->key.data());
183#endif
184
185    delete lock;
186}
187
188//-------------------------------------------------------------------
189
190void
191process::remove(int a_key)
192{
193#ifdef XSI_IPC
194    int keeper = semget(a_key, 1, S_IRUSR | S_IWUSR);
195    if (keeper == -1)
196        dodo_throw exception::basic(exception::MODULE_PCSYNCPROCESS, PROCESSEX_REMOVE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
197
198    if (semctl(keeper, 0, IPC_RMID) == -1)
199        dodo_throw exception::basic(exception::MODULE_PCSYNCPROCESS, PROCESSEX_REMOVE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
200#else
201    dodo::string key = "/";
202
203    char _key[4];
204    memcpy(_key, &a_key, 4);
205
206    key += dodo::string(tools::code::binToHex(dodo::string(_key, 4)));
207
208    if (sem_unlink(key.data()) == -1)
209        dodo_throw exception::basic(exception::MODULE_PCSYNCPROCESS, PROCESSEX_REMOVE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
210#endif
211}
212
213//-------------------------------------------------------------------
214
215bool
216process::acquire(unsigned long microseconds)
217{
218    int pid = getpid();
219
220    if (acquired() && pid == current) {
221        ++recursive;
222
223        return true;
224    }
225
226#ifdef XSI_IPC
227    lock->operations[0].sem_op = -1;
228
229    if (microseconds == 0) {
230        if (semop(lock->keeper, lock->operations, 1) != 0)
231            dodo_throw exception::basic(exception::MODULE_PCSYNCPROCESS, PROCESSEX_ACQUIRE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
232    } else {
233        timespec ts = {microseconds/1000000, (microseconds%1000000)*1000};
234
235        if (semtimedop(lock->keeper, lock->operations, 1, &ts) != 0) {
236            if (errno == EAGAIN)
237                return false;
238            else
239                dodo_throw exception::basic(exception::MODULE_PCSYNCPROCESS, PROCESSEX_ACQUIRE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
240        }
241    }
242#else
243    if (microseconds == 0) {
244        if (sem_wait(lock->keeper) != 0)
245            dodo_throw exception::basic(exception::MODULE_PCSYNCPROCESS, PROCESSEX_ACQUIRE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
246    } else {
247        timespec ts = {microseconds/1000000, (microseconds%1000000)*1000};
248        timespec now;
249
250        clock_gettime(CLOCK_REALTIME, &now);
251        ts.tv_sec += now.tv_sec;
252        ts.tv_nsec += now.tv_nsec;
253        if (ts.tv_nsec > 999999999) {
254            ts.tv_sec += 1;
255            ts.tv_nsec -= 999999999;
256        }
257
258        if (sem_timedwait(lock->keeper, &ts) != 0) {
259            if (errno == ETIMEDOUT)
260                return false;
261            else
262                dodo_throw exception::basic(exception::MODULE_PCSYNCPROCESS, PROCESSEX_ACQUIRE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
263        }
264    }
265#endif
266
267    current = pid;
268    recursive = 0;
269
270    return true;
271}
272
273//-------------------------------------------------------------------
274
275void
276process::release()
277{
278    if (acquired() && current == getpid() && recursive > 0) {
279        --recursive;
280
281        return;
282    }
283
284#ifdef XSI_IPC
285    lock->operations[0].sem_op = 1;
286
287    if (semop(lock->keeper, lock->operations, 1) != 0)
288        dodo_throw exception::basic(exception::MODULE_PCSYNCPROCESS, PROCESSEX_RELEASE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
289#else
290    if (sem_post(lock->keeper) != 0)
291        dodo_throw exception::basic(exception::MODULE_PCSYNCPROCESS, PROCESSEX_RELEASE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
292#endif
293
294    current = 0;
295}
296
297//-------------------------------------------------------------------
298
299bool
300process::acquired()
301{
302    int value;
303
304#ifdef XSI_IPC
305    value = semctl(lock->keeper, 0, GETVAL, 0);
306    if (value == -1)
307        dodo_throw exception::basic(exception::MODULE_PCSYNCPROCESS, PROCESSEX_ACQUIRED, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
308#else
309    if (sem_getvalue(lock->keeper, &value) != 0)
310        dodo_throw exception::basic(exception::MODULE_PCSYNCPROCESS, PROCESSEX_ACQUIRED, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
311#endif
312
313    return (value == 0);
314}
315
316//-------------------------------------------------------------------
317
Note: See TracBrowser for help on using the repository browser.