1 | // |
2 | // NamedMutex_UNIX.cpp |
3 | // |
4 | // Library: Foundation |
5 | // Package: Processes |
6 | // Module: NamedMutex |
7 | // |
8 | // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/NamedMutex_UNIX.h" |
16 | #include "Poco/Format.h" |
17 | #include "Poco/Exception.h" |
18 | #include <fcntl.h> |
19 | #include <sys/stat.h> |
20 | #include <errno.h> |
21 | #if defined(sun) || defined(__APPLE__) || defined(__osf__) || defined(_AIX) || defined(__EMSCRIPTEN__) |
22 | #include <semaphore.h> |
23 | #else |
24 | #include <unistd.h> |
25 | #include <sys/types.h> |
26 | #include <sys/ipc.h> |
27 | #include <sys/sem.h> |
28 | #endif |
29 | |
30 | |
31 | namespace Poco { |
32 | |
33 | |
34 | #if (POCO_OS == POCO_OS_LINUX) || (POCO_OS == POCO_OS_CYGWIN) || (POCO_OS == POCO_OS_FREE_BSD) || (POCO_OS == POCO_OS_NACL) |
35 | union semun |
36 | { |
37 | int val; |
38 | struct semid_ds* buf; |
39 | unsigned short int* array; |
40 | struct seminfo* __buf; |
41 | }; |
42 | #elif (POCO_OS == POCO_OS_HPUX) |
43 | union semun |
44 | { |
45 | int val; |
46 | struct semid_ds* buf; |
47 | ushort* array; |
48 | }; |
49 | #endif |
50 | |
51 | |
52 | NamedMutexImpl::NamedMutexImpl(const std::string& name): |
53 | _name(name) |
54 | { |
55 | std::string fileName = getFileName(); |
56 | #if defined(sun) || defined(__APPLE__) || defined(__osf__) || defined(__QNX__) || defined(_AIX) || defined(__EMSCRIPTEN__) |
57 | _sem = sem_open(fileName.c_str(), O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO, 1); |
58 | if ((long) _sem == (long) SEM_FAILED) |
59 | throw SystemException(Poco::format("cannot create named mutex %s (sem_open() failed, errno=%d)" , fileName, errno), _name); |
60 | #else |
61 | int fd = open(fileName.c_str(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
62 | if (fd != -1) |
63 | close(fd); |
64 | else |
65 | throw SystemException(Poco::format("cannot create named mutex %s (lockfile)" , fileName), _name); |
66 | key_t key = ftok(fileName.c_str(), 'p'); |
67 | if (key == -1) |
68 | throw SystemException(Poco::format("cannot create named mutex %s (ftok() failed, errno=%d)" , fileName, errno), _name); |
69 | _semid = semget(key, 1, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH | IPC_CREAT | IPC_EXCL); |
70 | if (_semid >= 0) |
71 | { |
72 | union semun arg; |
73 | arg.val = 1; |
74 | semctl(_semid, 0, SETVAL, arg); |
75 | _owned = true; |
76 | return; |
77 | } |
78 | else if (errno == EEXIST) |
79 | { |
80 | _semid = semget(key, 1, 0); |
81 | _owned = false; |
82 | if (_semid >= 0) return; |
83 | } |
84 | |
85 | throw SystemException(Poco::format("cannot create named mutex %s (semget() failed, errno=%d)" , fileName, errno), _name); |
86 | #endif // defined(sun) || defined(__APPLE__) || defined(__osf__) || defined(__QNX__) || defined(_AIX) || defined(__EMSCRIPTEN__) |
87 | } |
88 | |
89 | |
90 | NamedMutexImpl::~NamedMutexImpl() |
91 | { |
92 | #if defined(sun) || defined(__APPLE__) || defined(__osf__) || defined(__QNX__) || defined(_AIX) || defined(__EMSCRIPTEN__) |
93 | sem_close(_sem); |
94 | #else |
95 | if (_owned) semctl(_semid, 0, IPC_RMID, 0); |
96 | #endif |
97 | } |
98 | |
99 | |
100 | void NamedMutexImpl::lockImpl() |
101 | { |
102 | #if defined(sun) || defined(__APPLE__) || defined(__osf__) || defined(__QNX__) || defined(_AIX) || defined(__EMSCRIPTEN__) |
103 | int err; |
104 | do |
105 | { |
106 | err = sem_wait(_sem); |
107 | } |
108 | while (err && errno == EINTR); |
109 | if (err) throw SystemException("cannot lock named mutex" , _name); |
110 | #else |
111 | struct sembuf op; |
112 | op.sem_num = 0; |
113 | op.sem_op = -1; |
114 | op.sem_flg = SEM_UNDO; |
115 | int err; |
116 | do |
117 | { |
118 | err = semop(_semid, &op, 1); |
119 | } |
120 | while (err && errno == EINTR); |
121 | if (err) throw SystemException("cannot lock named mutex" , _name); |
122 | #endif |
123 | } |
124 | |
125 | |
126 | bool NamedMutexImpl::tryLockImpl() |
127 | { |
128 | #if defined(sun) || defined(__APPLE__) || defined(__osf__) || defined(__QNX__) || defined(_AIX) || defined(__EMSCRIPTEN__) |
129 | return sem_trywait(_sem) == 0; |
130 | #else |
131 | struct sembuf op; |
132 | op.sem_num = 0; |
133 | op.sem_op = -1; |
134 | op.sem_flg = SEM_UNDO | IPC_NOWAIT; |
135 | return semop(_semid, &op, 1) == 0; |
136 | #endif |
137 | } |
138 | |
139 | |
140 | void NamedMutexImpl::unlockImpl() |
141 | { |
142 | #if defined(sun) || defined(__APPLE__) || defined(__osf__) || defined(__QNX__) || defined(_AIX) || defined(__EMSCRIPTEN__) |
143 | if (sem_post(_sem) != 0) |
144 | throw SystemException("cannot unlock named mutex" , _name); |
145 | #else |
146 | struct sembuf op; |
147 | op.sem_num = 0; |
148 | op.sem_op = 1; |
149 | op.sem_flg = SEM_UNDO; |
150 | if (semop(_semid, &op, 1) != 0) |
151 | throw SystemException("cannot unlock named mutex" , _name); |
152 | #endif |
153 | } |
154 | |
155 | |
156 | std::string NamedMutexImpl::getFileName() |
157 | { |
158 | #if defined(sun) || defined(__APPLE__) || defined(__QNX__) |
159 | std::string fn = "/" ; |
160 | #else |
161 | std::string fn = "/tmp/" ; |
162 | #endif |
163 | fn.append(_name); |
164 | fn.append(".mutex" ); |
165 | return fn; |
166 | } |
167 | |
168 | |
169 | } // namespace Poco |
170 | |
171 | |