Skip to content

Commit daa171d

Browse files
fix: replace deprecated POSIX semaphores with pthread wrapper (#516)
macOS deprecated unnamed POSIX semaphores (sem_init, sem_getvalue). Replace with a portable spine_sem_t wrapper using pthread mutex + condition variable. This eliminates all 9 deprecation warnings and works identically on Linux and macOS. Spine uses semaphores only as atomic counters (sem_post + sem_getvalue, no sem_wait), so the wrapper is straightforward. The condition variable is included for completeness but not currently exercised. Changes: - Add spine_sem.h with inline spine_sem_init/post/getvalue/wait/destroy - Replace semaphore.h include with spine_sem.h in common.h - Update all sem_t/sem_init/sem_post/sem_getvalue calls in spine.c, poller.c, and spine.h - Add spine_sem.h to EXTRA_DIST Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
1 parent df0093d commit daa171d

File tree

6 files changed

+99
-22
lines changed

6 files changed

+99
-22
lines changed

Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ bin_PROGRAMS = spine
3131

3232
man_MANS = spine.1
3333

34-
EXTRA_DIST = spine.1 uthash.h
34+
EXTRA_DIST = spine.1 uthash.h spine_sem.h
3535

3636
# Docker targets — require Dockerfile and Dockerfile.dev (from PR #401)
3737
.PHONY: docker docker-dev verify cppcheck

common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
#include <math.h>
8888
#include <mysql.h>
8989
#include <netdb.h>
90-
#include <semaphore.h>
90+
#include "spine_sem.h"
9191
#include <signal.h>
9292
#include <stdarg.h>
9393
#include <stdio.h>

poller.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,19 @@ void child_cleanup(void *arg) {
4343
}
4444

4545
void child_cleanup_thread(void *arg) {
46-
sem_post(&available_threads);
46+
spine_sem_post(&available_threads);
4747

4848
int a_threads_value;
49-
sem_getvalue(&available_threads, &a_threads_value);
49+
spine_sem_getvalue(&available_threads, &a_threads_value);
5050

5151
SPINE_LOG_DEVDBG(("DEBUG: Available Threads is %i (%i outstanding)", a_threads_value, set.threads - a_threads_value));
5252
}
5353

5454
void child_cleanup_script(void *arg) {
55-
sem_post(&available_scripts);
55+
spine_sem_post(&available_scripts);
5656

5757
int a_scripts_value;
58-
sem_getvalue(&available_scripts, &a_scripts_value);
58+
spine_sem_getvalue(&available_scripts, &a_scripts_value);
5959

6060
SPINE_LOG_DEVDBG(("DEBUG: Available Scripts is %i (%i outstanding)", a_scripts_value, MAX_SIMULTANEOUS_SCRIPTS - a_scripts_value));
6161
}
@@ -97,7 +97,7 @@ void *child(void *arg) {
9797
thread_mutex_unlock(LOCK_HOST_TIME);
9898

9999
/* Allows main thread to proceed with creation of other threads */
100-
sem_post(poller_details.thread_init_sem);
100+
spine_sem_post(poller_details.thread_init_sem);
101101

102102
SPINE_LOG_DEV(host_id, DEBUG, ("DEBUG: Device[%i] HT[%i] In Poller, About to Start Polling", host_id, host_thread));
103103

spine.c

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,8 @@
101101
/* Global Variables */
102102
int entries = 0;
103103
int num_hosts = 0;
104-
sem_t available_threads;
105-
sem_t available_scripts;
104+
spine_sem_t available_threads;
105+
spine_sem_t available_scripts;
106106
double start_time;
107107
double total_time;
108108

@@ -201,7 +201,7 @@ int main(int argc, char *argv[]) {
201201
double host_time_double = 0;
202202
int items_per_thread = 0;
203203
int device_threads;
204-
sem_t thread_init_sem;
204+
spine_sem_t thread_init_sem;
205205
int a_threads_value;
206206
//struct timespec until_spec;
207207

@@ -694,19 +694,19 @@ int main(int argc, char *argv[]) {
694694
init_mutexes();
695695

696696
/* initialize available_threads semaphore */
697-
sem_init(&available_threads, 0, set.threads);
697+
spine_sem_init(&available_threads, set.threads);
698698

699699
/* initialize available_scripts semaphore */
700-
sem_init(&available_scripts, 0, MAX_SIMULTANEOUS_SCRIPTS);
700+
spine_sem_init(&available_scripts, MAX_SIMULTANEOUS_SCRIPTS);
701701

702702
/* initialize thread initialization semaphore */
703-
sem_init(&thread_init_sem, 0, 1);
703+
spine_sem_init(&thread_init_sem, 1);
704704

705705
/* specify the point of timeout for timedwait semaphores */
706706
//until_spec.tv_sec = (time_t)(set.poller_interval + begin_time - 0.2);
707707
//until_spec.tv_nsec = 0;
708708

709-
sem_getvalue(&available_threads, &a_threads_value);
709+
spine_sem_getvalue(&available_threads, &a_threads_value);
710710
SPINE_LOG_HIGH(("DEBUG: Initial Value of Available Threads is %i (%i outstanding)", a_threads_value, set.threads - a_threads_value));
711711

712712
/* tell fork processes that they are now active */
@@ -935,10 +935,10 @@ int main(int argc, char *argv[]) {
935935
device_counter++;
936936
}
937937

938-
sem_getvalue(&available_threads, &a_threads_value);
938+
spine_sem_getvalue(&available_threads, &a_threads_value);
939939
SPINE_LOG_HIGH(("DEBUG: Device[%i] Available Threads is %i (%i outstanding)", poller_details->host_id, a_threads_value, set.threads - a_threads_value));
940940

941-
sem_post(&thread_init_sem);
941+
spine_sem_post(&thread_init_sem);
942942

943943
SPINE_LOG_DEVDBG(("DEBUG: DTS: device = %d, host_id = %d, host_thread = %d,"
944944
" host_threads = %d, host_data_ids = %d, complete = %d",
@@ -959,12 +959,12 @@ int main(int argc, char *argv[]) {
959959
/* Restore thread initialization semaphore if thread creation failed */
960960
if (thread_status) {
961961
thread_mutex_unlock(LOCK_HOST_TIME);
962-
sem_post(&thread_init_sem);
962+
spine_sem_post(&thread_init_sem);
963963
}
964964
}
965965
}
966966

967-
sem_getvalue(&available_threads, &a_threads_value);
967+
spine_sem_getvalue(&available_threads, &a_threads_value);
968968

969969
/* wait for all threads to 'complete'
970970
* using the mutex here as the semaphore will
@@ -979,7 +979,7 @@ int main(int argc, char *argv[]) {
979979

980980
SPINE_LOG_HIGH(("NOTE: Polling sleeping while waiting for %d Threads to End", set.threads - a_threads_value));
981981
usleep(500000);
982-
sem_getvalue(&available_threads, &a_threads_value);
982+
spine_sem_getvalue(&available_threads, &a_threads_value);
983983
}
984984

985985
threads_final = set.threads - a_threads_value;

spine.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ typedef struct poller_thread {
507507
int complete;
508508
char host_time[40];
509509
double host_time_double;
510-
sem_t *thread_init_sem;
510+
spine_sem_t *thread_init_sem;
511511
} poller_thread_t;
512512

513513
/*! PHP Script Server Structure
@@ -638,8 +638,8 @@ extern config_t set;
638638
extern php_t *php_processes;
639639
extern char start_datetime[20];
640640
extern char config_paths[CONFIG_PATHS][BUFSIZE];
641-
extern sem_t available_threads;
642-
extern sem_t available_scripts;
641+
extern spine_sem_t available_threads;
642+
extern spine_sem_t available_scripts;
643643
extern pool_t *db_pool_remote;
644644
extern pool_t *db_pool_local;
645645

spine_sem.h

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
+-------------------------------------------------------------------------+
3+
| Copyright (C) 2004-2026 The Cacti Group |
4+
| |
5+
| This program is free software; you can redistribute it and/or |
6+
| modify it under the terms of the GNU General Public License |
7+
| as published by the Free Software Foundation; either version 2 |
8+
| of the License, or (at your option) any later version. |
9+
+-------------------------------------------------------------------------+
10+
| Cacti: The Complete RRDtool-based Graphing Solution |
11+
+-------------------------------------------------------------------------+
12+
*/
13+
14+
#ifndef SPINE_SEM_H
15+
#define SPINE_SEM_H
16+
17+
/*
18+
* Portable counting semaphore using pthreads.
19+
*
20+
* macOS deprecated unnamed POSIX semaphores (sem_init, sem_getvalue).
21+
* This wrapper provides the same counting semantics using a pthread
22+
* mutex + condition variable, which works on all POSIX platforms.
23+
*
24+
* Spine uses semaphores only as atomic counters (sem_post + sem_getvalue
25+
* with no sem_wait), so the condition variable is included for
26+
* completeness but is not currently exercised.
27+
*/
28+
29+
#include <pthread.h>
30+
31+
typedef struct {
32+
pthread_mutex_t mutex;
33+
pthread_cond_t cond;
34+
int value;
35+
} spine_sem_t;
36+
37+
static inline int spine_sem_init(spine_sem_t *s, int value) {
38+
if (pthread_mutex_init(&s->mutex, NULL) != 0) return -1;
39+
if (pthread_cond_init(&s->cond, NULL) != 0) {
40+
pthread_mutex_destroy(&s->mutex);
41+
return -1;
42+
}
43+
s->value = value;
44+
return 0;
45+
}
46+
47+
static inline int spine_sem_post(spine_sem_t *s) {
48+
pthread_mutex_lock(&s->mutex);
49+
s->value++;
50+
pthread_cond_signal(&s->cond);
51+
pthread_mutex_unlock(&s->mutex);
52+
return 0;
53+
}
54+
55+
static inline int spine_sem_getvalue(spine_sem_t *s, int *val) {
56+
pthread_mutex_lock(&s->mutex);
57+
*val = s->value;
58+
pthread_mutex_unlock(&s->mutex);
59+
return 0;
60+
}
61+
62+
static inline int spine_sem_wait(spine_sem_t *s) {
63+
pthread_mutex_lock(&s->mutex);
64+
while (s->value <= 0)
65+
pthread_cond_wait(&s->cond, &s->mutex);
66+
s->value--;
67+
pthread_mutex_unlock(&s->mutex);
68+
return 0;
69+
}
70+
71+
static inline int spine_sem_destroy(spine_sem_t *s) {
72+
pthread_mutex_destroy(&s->mutex);
73+
pthread_cond_destroy(&s->cond);
74+
return 0;
75+
}
76+
77+
#endif /* SPINE_SEM_H */

0 commit comments

Comments
 (0)