1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **/
19
20 #include "common.h"
21 #include "log.h"
22 #include "mutexs.h"
23
24 #ifdef _WINDOWS
25 # include "sysinfo.h"
26 #else
27 #ifdef HAVE_PTHREAD_PROCESS_SHARED
28 typedef struct
29 {
30 pthread_mutex_t mutexes[ZBX_MUTEX_COUNT];
31 pthread_rwlock_t rwlocks[ZBX_RWLOCK_COUNT];
32 }
33 zbx_shared_lock_t;
34
35 static zbx_shared_lock_t *shared_lock;
36 static int shm_id, locks_disabled;
37 #else
38 # if !HAVE_SEMUN
39 union semun
40 {
41 int val; /* value for SETVAL */
42 struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */
43 unsigned short int *array; /* array for GETALL & SETALL */
44 struct seminfo *__buf; /* buffer for IPC_INFO */
45 };
46
47 # undef HAVE_SEMUN
48 # define HAVE_SEMUN 1
49 # endif /* HAVE_SEMUN */
50
51 # include "cfg.h"
52 # include "threads.h"
53
54 static int ZBX_SEM_LIST_ID;
55 static unsigned char mutexes;
56 #endif
57
58 /******************************************************************************
59 * *
60 * Function: zbx_locks_create *
61 * *
62 * Purpose: if pthread mutexes and read-write locks can be shared between *
63 * processes then create them, otherwise fallback to System V *
64 * semaphore operations *
65 * *
66 * Parameters: error - dynamically allocated memory with error message. *
67 * *
68 * Return value: SUCCEED if mutexes successfully created, otherwise FAIL *
69 * *
70 ******************************************************************************/
zbx_locks_create(char ** error)71 int zbx_locks_create(char **error)
72 {
73 #ifdef HAVE_PTHREAD_PROCESS_SHARED
74 int i;
75 pthread_mutexattr_t mta;
76 pthread_rwlockattr_t rwa;
77
78 if (-1 == (shm_id = shmget(IPC_PRIVATE, ZBX_SIZE_T_ALIGN8(sizeof(zbx_shared_lock_t)),
79 IPC_CREAT | IPC_EXCL | 0600)))
80 {
81 *error = zbx_dsprintf(*error, "cannot allocate shared memory for locks");
82 return FAIL;
83 }
84
85 if ((void *)(-1) == (shared_lock = (zbx_shared_lock_t *)shmat(shm_id, NULL, 0)))
86 {
87 *error = zbx_dsprintf(*error, "cannot attach shared memory for locks: %s", zbx_strerror(errno));
88 return FAIL;
89 }
90
91 memset(shared_lock, 0, sizeof(zbx_shared_lock_t));
92
93 /* immediately mark the new shared memory for destruction after attaching to it */
94 if (-1 == shmctl(shm_id, IPC_RMID, 0))
95 {
96 *error = zbx_dsprintf(*error, "cannot mark the new shared memory for destruction: %s",
97 zbx_strerror(errno));
98 return FAIL;
99 }
100
101 if (0 != pthread_mutexattr_init(&mta))
102 {
103 *error = zbx_dsprintf(*error, "cannot initialize mutex attribute: %s", zbx_strerror(errno));
104 return FAIL;
105 }
106
107 if (0 != pthread_mutexattr_setpshared(&mta, PTHREAD_PROCESS_SHARED))
108 {
109 *error = zbx_dsprintf(*error, "cannot set shared mutex attribute: %s", zbx_strerror(errno));
110 return FAIL;
111 }
112
113 for (i = 0; i < ZBX_MUTEX_COUNT; i++)
114 {
115 if (0 != pthread_mutex_init(&shared_lock->mutexes[i], &mta))
116 {
117 *error = zbx_dsprintf(*error, "cannot create mutex: %s", zbx_strerror(errno));
118 return FAIL;
119 }
120 }
121
122 if (0 != pthread_rwlockattr_init(&rwa))
123 {
124 *error = zbx_dsprintf(*error, "cannot initialize read write lock attribute: %s", zbx_strerror(errno));
125 return FAIL;
126 }
127
128 if (0 != pthread_rwlockattr_setpshared(&rwa, PTHREAD_PROCESS_SHARED))
129 {
130 *error = zbx_dsprintf(*error, "cannot set shared read write lock attribute: %s", zbx_strerror(errno));
131 return FAIL;
132 }
133
134 for (i = 0; i < ZBX_RWLOCK_COUNT; i++)
135 {
136 if (0 != pthread_rwlock_init(&shared_lock->rwlocks[i], &rwa))
137 {
138 *error = zbx_dsprintf(*error, "cannot create rwlock: %s", zbx_strerror(errno));
139 return FAIL;
140 }
141 }
142 #else
143 union semun semopts;
144 int i;
145
146 if (-1 == (ZBX_SEM_LIST_ID = semget(IPC_PRIVATE, ZBX_MUTEX_COUNT + ZBX_RWLOCK_COUNT, 0600)))
147 {
148 *error = zbx_dsprintf(*error, "cannot create semaphore set: %s", zbx_strerror(errno));
149 return FAIL;
150 }
151
152 /* set default semaphore value */
153
154 semopts.val = 1;
155 for (i = 0; ZBX_MUTEX_COUNT + ZBX_RWLOCK_COUNT > i; i++)
156 {
157 if (-1 != semctl(ZBX_SEM_LIST_ID, i, SETVAL, semopts))
158 continue;
159
160 *error = zbx_dsprintf(*error, "cannot initialize semaphore: %s", zbx_strerror(errno));
161
162 if (-1 == semctl(ZBX_SEM_LIST_ID, 0, IPC_RMID, 0))
163 zbx_error("cannot remove semaphore set %d: %s", ZBX_SEM_LIST_ID, zbx_strerror(errno));
164
165 ZBX_SEM_LIST_ID = -1;
166
167 return FAIL;
168 }
169 #endif
170 return SUCCEED;
171 }
172
173 /******************************************************************************
174 * *
175 * Function: zbx_mutex_addr_get *
176 * *
177 * Purpose: acquire address of the mutex *
178 * *
179 * Parameters: mutex_name - name of the mutex to return address for *
180 * *
181 * Return value: address of the mutex *
182 * *
183 ******************************************************************************/
zbx_mutex_addr_get(zbx_mutex_name_t mutex_name)184 zbx_mutex_t zbx_mutex_addr_get(zbx_mutex_name_t mutex_name)
185 {
186 #ifdef HAVE_PTHREAD_PROCESS_SHARED
187 return &shared_lock->mutexes[mutex_name];
188 #else
189 return mutex_name;
190 #endif
191 }
192
193 /******************************************************************************
194 * *
195 * Function: zbx_mutex_addr_get *
196 * *
197 * Purpose: acquire address of the rwlock *
198 * *
199 * Parameters: rwlock_name - name of the rwlock to return address for *
200 * *
201 * Return value: address of the rwlock *
202 * *
203 ******************************************************************************/
zbx_rwlock_addr_get(zbx_rwlock_name_t rwlock_name)204 zbx_rwlock_t zbx_rwlock_addr_get(zbx_rwlock_name_t rwlock_name)
205 {
206 #ifdef HAVE_PTHREAD_PROCESS_SHARED
207 return &shared_lock->rwlocks[rwlock_name];
208 #else
209 return rwlock_name + ZBX_MUTEX_COUNT;
210 #endif
211 }
212
213 /******************************************************************************
214 * *
215 * Function: zbx_rwlock_create *
216 * *
217 * Purpose: read-write locks are created using zbx_locks_create() function *
218 * this is only to obtain handle, if read write locks are not *
219 * supported, then outputs numeric handle of mutex that can be used *
220 * with mutex handling functions *
221 * *
222 * Parameters: rwlock - read-write lock handle if supported, otherwise mutex *
223 * name - name of read-write lock (index for nix system) *
224 * error - unused *
225 * *
226 * Return value: SUCCEED if mutexes successfully created, otherwise FAIL *
227 * *
228 ******************************************************************************/
zbx_rwlock_create(zbx_rwlock_t * rwlock,zbx_rwlock_name_t name,char ** error)229 int zbx_rwlock_create(zbx_rwlock_t *rwlock, zbx_rwlock_name_t name, char **error)
230 {
231 ZBX_UNUSED(error);
232 #ifdef HAVE_PTHREAD_PROCESS_SHARED
233 *rwlock = &shared_lock->rwlocks[name];
234 #else
235 *rwlock = name + ZBX_MUTEX_COUNT;
236 mutexes++;
237 #endif
238 return SUCCEED;
239 }
240 #ifdef HAVE_PTHREAD_PROCESS_SHARED
241 /******************************************************************************
242 * *
243 * Function: __zbx_rwlock_wrlock *
244 * *
245 * Purpose: acquire write lock for read-write lock (exclusive access) *
246 * *
247 * Parameters: rwlock - handle of read-write lock *
248 * *
249 ******************************************************************************/
__zbx_rwlock_wrlock(const char * filename,int line,zbx_rwlock_t rwlock)250 void __zbx_rwlock_wrlock(const char *filename, int line, zbx_rwlock_t rwlock)
251 {
252 if (ZBX_RWLOCK_NULL == rwlock)
253 return;
254
255 if (0 != locks_disabled)
256 return;
257
258 if (0 != pthread_rwlock_wrlock(rwlock))
259 {
260 zbx_error("[file:'%s',line:%d] write lock failed: %s", filename, line, zbx_strerror(errno));
261 exit(EXIT_FAILURE);
262 }
263 }
264
265 /******************************************************************************
266 * *
267 * Function: __zbx_rwlock_rdlock *
268 * *
269 * Purpose: acquire read lock for read-write lock (there can be many readers) *
270 * *
271 * Parameters: rwlock - handle of read-write lock *
272 * *
273 ******************************************************************************/
__zbx_rwlock_rdlock(const char * filename,int line,zbx_rwlock_t rwlock)274 void __zbx_rwlock_rdlock(const char *filename, int line, zbx_rwlock_t rwlock)
275 {
276 if (ZBX_RWLOCK_NULL == rwlock)
277 return;
278
279 if (0 != locks_disabled)
280 return;
281
282 if (0 != pthread_rwlock_rdlock(rwlock))
283 {
284 zbx_error("[file:'%s',line:%d] read lock failed: %s", filename, line, zbx_strerror(errno));
285 exit(EXIT_FAILURE);
286 }
287 }
288
289 /******************************************************************************
290 * *
291 * Function: __zbx_rwlock_unlock *
292 * *
293 * Purpose: unlock read-write lock *
294 * *
295 * Parameters: rwlock - handle of read-write lock *
296 * *
297 ******************************************************************************/
__zbx_rwlock_unlock(const char * filename,int line,zbx_rwlock_t rwlock)298 void __zbx_rwlock_unlock(const char *filename, int line, zbx_rwlock_t rwlock)
299 {
300 if (ZBX_RWLOCK_NULL == rwlock)
301 return;
302
303 if (0 != locks_disabled)
304 return;
305
306 if (0 != pthread_rwlock_unlock(rwlock))
307 {
308 zbx_error("[file:'%s',line:%d] read-write lock unlock failed: %s", filename, line, zbx_strerror(errno));
309 exit(EXIT_FAILURE);
310 }
311 }
312
313 /******************************************************************************
314 * *
315 * Function: zbx_rwlock_destroy *
316 * *
317 * Purpose: Destroy read-write lock *
318 * *
319 * Parameters: rwlock - handle of read-write lock *
320 * *
321 * *
322 ******************************************************************************/
323
zbx_rwlock_destroy(zbx_rwlock_t * rwlock)324 void zbx_rwlock_destroy(zbx_rwlock_t *rwlock)
325 {
326 if (ZBX_RWLOCK_NULL == *rwlock)
327 return;
328
329 if (0 != locks_disabled)
330 return;
331
332 if (0 != pthread_rwlock_destroy(*rwlock))
333 zbx_error("cannot remove read-write lock: %s", zbx_strerror(errno));
334
335 *rwlock = ZBX_RWLOCK_NULL;
336 }
337
338 /******************************************************************************
339 * *
340 * Function: zbx_locks_disable *
341 * *
342 * Purpose: disable locks *
343 * *
344 ******************************************************************************/
zbx_locks_disable(void)345 void zbx_locks_disable(void)
346 {
347 /* attempting to destroy a locked pthread mutex results in undefined behavior */
348 locks_disabled = 1;
349 }
350 #endif
351 #endif /* _WINDOWS */
352
353 /******************************************************************************
354 * *
355 * Function: zbx_mutex_create *
356 * *
357 * Purpose: Create the mutex *
358 * *
359 * Parameters: mutex - handle of mutex *
360 * name - name of mutex (index for nix system) *
361 * *
362 * Return value: If the function succeeds, then return SUCCEED, *
363 * FAIL on an error *
364 * *
365 * Author: Eugene Grigorjev *
366 * *
367 ******************************************************************************/
zbx_mutex_create(zbx_mutex_t * mutex,zbx_mutex_name_t name,char ** error)368 int zbx_mutex_create(zbx_mutex_t *mutex, zbx_mutex_name_t name, char **error)
369 {
370 #ifdef _WINDOWS
371 if (NULL == (*mutex = CreateMutex(NULL, FALSE, name)))
372 {
373 *error = zbx_dsprintf(*error, "error on mutex creating: %s", strerror_from_system(GetLastError()));
374 return FAIL;
375 }
376 #else
377 ZBX_UNUSED(error);
378 #ifdef HAVE_PTHREAD_PROCESS_SHARED
379 *mutex = &shared_lock->mutexes[name];
380 #else
381 mutexes++;
382 *mutex = name;
383 #endif
384 #endif
385 return SUCCEED;
386 }
387
388 /******************************************************************************
389 * *
390 * Function: zbx_mutex_lock *
391 * *
392 * Purpose: Waits until the mutex is in the signalled state *
393 * *
394 * Parameters: mutex - handle of mutex *
395 * *
396 * Author: Eugene Grigorjev, Alexander Vladishev *
397 * *
398 ******************************************************************************/
__zbx_mutex_lock(const char * filename,int line,zbx_mutex_t mutex)399 void __zbx_mutex_lock(const char *filename, int line, zbx_mutex_t mutex)
400 {
401 #ifndef _WINDOWS
402 #ifndef HAVE_PTHREAD_PROCESS_SHARED
403 struct sembuf sem_lock;
404 #endif
405 #else
406 DWORD dwWaitResult;
407 #endif
408
409 if (ZBX_MUTEX_NULL == mutex)
410 return;
411
412 #ifdef _WINDOWS
413 #ifdef ZABBIX_AGENT
414 if (0 != (ZBX_MUTEX_THREAD_DENIED & get_thread_global_mutex_flag()))
415 {
416 zbx_error("[file:'%s',line:%d] lock failed: ZBX_MUTEX_THREAD_DENIED is set for thread with id = %d",
417 filename, line, zbx_get_thread_id());
418 exit(EXIT_FAILURE);
419 }
420 #endif
421 dwWaitResult = WaitForSingleObject(mutex, INFINITE);
422
423 switch (dwWaitResult)
424 {
425 case WAIT_OBJECT_0:
426 break;
427 case WAIT_ABANDONED:
428 THIS_SHOULD_NEVER_HAPPEN;
429 exit(EXIT_FAILURE);
430 default:
431 zbx_error("[file:'%s',line:%d] lock failed: %s",
432 filename, line, strerror_from_system(GetLastError()));
433 exit(EXIT_FAILURE);
434 }
435 #else
436 #ifdef HAVE_PTHREAD_PROCESS_SHARED
437 if (0 != locks_disabled)
438 return;
439
440 if (0 != pthread_mutex_lock(mutex))
441 {
442 zbx_error("[file:'%s',line:%d] lock failed: %s", filename, line, zbx_strerror(errno));
443 exit(EXIT_FAILURE);
444 }
445 #else
446 sem_lock.sem_num = mutex;
447 sem_lock.sem_op = -1;
448 sem_lock.sem_flg = SEM_UNDO;
449
450 while (-1 == semop(ZBX_SEM_LIST_ID, &sem_lock, 1))
451 {
452 if (EINTR != errno)
453 {
454 zbx_error("[file:'%s',line:%d] lock failed: %s", filename, line, zbx_strerror(errno));
455 exit(EXIT_FAILURE);
456 }
457 }
458 #endif
459 #endif
460 }
461
462 /******************************************************************************
463 * *
464 * Function: zbx_mutex_unlock *
465 * *
466 * Purpose: Unlock the mutex *
467 * *
468 * Parameters: mutex - handle of mutex *
469 * *
470 * Author: Eugene Grigorjev, Alexander Vladishev *
471 * *
472 ******************************************************************************/
__zbx_mutex_unlock(const char * filename,int line,zbx_mutex_t mutex)473 void __zbx_mutex_unlock(const char *filename, int line, zbx_mutex_t mutex)
474 {
475 #ifndef _WINDOWS
476 #ifndef HAVE_PTHREAD_PROCESS_SHARED
477 struct sembuf sem_unlock;
478 #endif
479 #endif
480
481 if (ZBX_MUTEX_NULL == mutex)
482 return;
483
484 #ifdef _WINDOWS
485 if (0 == ReleaseMutex(mutex))
486 {
487 zbx_error("[file:'%s',line:%d] unlock failed: %s",
488 filename, line, strerror_from_system(GetLastError()));
489 exit(EXIT_FAILURE);
490 }
491 #else
492 #ifdef HAVE_PTHREAD_PROCESS_SHARED
493 if (0 != locks_disabled)
494 return;
495
496 if (0 != pthread_mutex_unlock(mutex))
497 {
498 zbx_error("[file:'%s',line:%d] unlock failed: %s", filename, line, zbx_strerror(errno));
499 exit(EXIT_FAILURE);
500 }
501 #else
502 sem_unlock.sem_num = mutex;
503 sem_unlock.sem_op = 1;
504 sem_unlock.sem_flg = SEM_UNDO;
505
506 while (-1 == semop(ZBX_SEM_LIST_ID, &sem_unlock, 1))
507 {
508 if (EINTR != errno)
509 {
510 zbx_error("[file:'%s',line:%d] unlock failed: %s", filename, line, zbx_strerror(errno));
511 exit(EXIT_FAILURE);
512 }
513 }
514 #endif
515 #endif
516 }
517
518 /******************************************************************************
519 * *
520 * Function: zbx_mutex_destroy *
521 * *
522 * Purpose: Destroy the mutex *
523 * *
524 * Parameters: mutex - handle of mutex *
525 * *
526 * Author: Eugene Grigorjev *
527 * *
528 ******************************************************************************/
zbx_mutex_destroy(zbx_mutex_t * mutex)529 void zbx_mutex_destroy(zbx_mutex_t *mutex)
530 {
531 #ifdef _WINDOWS
532 if (ZBX_MUTEX_NULL == *mutex)
533 return;
534
535 if (0 == CloseHandle(*mutex))
536 zbx_error("error on mutex destroying: %s", strerror_from_system(GetLastError()));
537 #else
538 #ifdef HAVE_PTHREAD_PROCESS_SHARED
539 if (0 != locks_disabled)
540 return;
541
542 if (0 != pthread_mutex_destroy(*mutex))
543 zbx_error("cannot remove mutex %p: %s", (void *)mutex, zbx_strerror(errno));
544 #else
545 if (0 == --mutexes && -1 == semctl(ZBX_SEM_LIST_ID, 0, IPC_RMID, 0))
546 zbx_error("cannot remove semaphore set %d: %s", ZBX_SEM_LIST_ID, zbx_strerror(errno));
547 #endif
548 #endif
549 *mutex = ZBX_MUTEX_NULL;
550 }
551
552 #ifdef _WINDOWS
553 /******************************************************************************
554 * *
555 * Function: zbx_mutex_create_per_process_name *
556 * *
557 * Purpose: Appends PID to the prefix of the mutex *
558 * *
559 * Parameters: prefix - mutex type *
560 * *
561 * Return value: Dynamically allocated, NUL terminated name of the mutex *
562 * *
563 * Comments: The mutex name must be shorter than MAX_PATH characters, *
564 * otherwise the function calls exit() *
565 * *
566 ******************************************************************************/
zbx_mutex_create_per_process_name(const zbx_mutex_name_t prefix)567 zbx_mutex_name_t zbx_mutex_create_per_process_name(const zbx_mutex_name_t prefix)
568 {
569 zbx_mutex_name_t name = ZBX_MUTEX_NULL;
570 int size;
571 wchar_t *format = L"%s_PID_%lx";
572 DWORD pid = GetCurrentProcessId();
573
574 /* exit if the mutex name length exceed the maximum allowed */
575 size = _scwprintf(format, prefix, pid);
576 if (MAX_PATH < size)
577 {
578 THIS_SHOULD_NEVER_HAPPEN;
579 exit(EXIT_FAILURE);
580 }
581
582 size = size + 1; /* for terminating '\0' */
583
584 name = zbx_malloc(NULL, sizeof(wchar_t) * size);
585 (void)_snwprintf_s(name, size, size - 1, format, prefix, pid);
586 name[size - 1] = L'\0';
587
588 return name;
589 }
590 #endif
591
592