#include <freeradius-devel/util/rb.h>
#include <freeradius-devel/util/syserror.h>
#include <freeradius-devel/server/trigger.h>
+#include <freeradius-devel/util/semaphore.h>
#include <pthread.h>
-/*
- * Other OS's have sem_init, OS X doesn't.
- */
-#ifdef HAVE_SEMAPHORE_H
-#include <semaphore.h>
-#endif
-
-#define SEMAPHORE_LOCKED (0)
-
-#ifdef __APPLE__
-#include <mach/task.h>
-#include <mach/mach_init.h>
-#include <mach/semaphore.h>
-
-#undef sem_t
-#define sem_t semaphore_t
-#undef sem_init
-#define sem_init(s,p,c) semaphore_create(mach_task_self(),s,SYNC_POLICY_FIFO,c)
-#undef sem_wait
-#define sem_wait(s) semaphore_wait(*s)
-#undef sem_post
-#define sem_post(s) semaphore_signal(*s)
-#undef sem_destroy
-#define sem_destroy(s) semaphore_destroy(mach_task_self(),*s)
-#endif /* __APPLE__ */
-
-#define SEM_WAIT_INTR(_x) do {if (sem_wait(_x) == 0) break;} while (errno == EINTR)
-
/**
* Track the child thread status.
*/
unsigned int num_workers_exited; //!< number of exited workers
- sem_t worker_sem; //!< for inter-thread signaling
- sem_t network_sem; //!< for inter-thread signaling
+ fr_sem_t *worker_sem; //!< for inter-thread signaling
+ fr_sem_t *network_sem; //!< for inter-thread signaling
fr_schedule_thread_instantiate_t worker_thread_instantiate; //!< thread instantiation callback
fr_schedule_thread_detach_t worker_thread_detach;
/*
* Tell the originator that the thread has started.
*/
- sem_post(&sc->worker_sem);
+ sem_post(sc->worker_sem);
/*
* Do all of the work.
/*
* Tell the scheduler we're done.
*/
- sem_post(&sc->worker_sem);
+ sem_post(sc->worker_sem);
talloc_free(ctx);
/*
* Tell the originator that the thread has started.
*/
- sem_post(&sc->network_sem);
+ sem_post(sc->network_sem);
DEBUG3("%s - Started", network_name);
/*
* Tell the scheduler we're done.
*/
- sem_post(&sc->network_sem);
+ sem_post(sc->network_sem);
talloc_free(ctx);
fr_dlist_init(&sc->workers, fr_schedule_worker_t, entry);
fr_dlist_init(&sc->networks, fr_schedule_network_t, entry);
- memset(&sc->network_sem, 0, sizeof(sc->network_sem));
- if (sem_init(&sc->network_sem, 0, SEMAPHORE_LOCKED) != 0) {
+ sc->network_sem = fr_sem_alloc();
+ if (!sc->network_sem) {
+ sem_fail:
ERROR("Failed creating semaphore: %s", fr_syserror(errno));
+ fr_sem_free(sc->network_sem);
talloc_free(sc);
return NULL;
}
- memset(&sc->worker_sem, 0, sizeof(sc->worker_sem));
- if (sem_init(&sc->worker_sem, 0, SEMAPHORE_LOCKED) != 0) {
- ERROR("Failed creating semaphore: %s", fr_syserror(errno));
- sem_destroy(&sc->network_sem);
- talloc_free(sc);
- return NULL;
- }
+ sc->worker_sem = fr_sem_alloc();
+ if (!sc->worker_sem) goto sem_fail;
/*
* Create the network threads first.
for (i = 0; i < (unsigned int)fr_dlist_num_elements(&sc->networks); i++) {
DEBUG3("Waiting for semaphore from network %u/%u",
i + 1, (unsigned int)fr_dlist_num_elements(&sc->networks));
- SEM_WAIT_INTR(&sc->network_sem);
+ SEM_WAIT_INTR(sc->network_sem);
}
/*
for (i = 0; i < (unsigned int)fr_dlist_num_elements(&sc->workers); i++) {
DEBUG3("Waiting for semaphore from worker %u/%u",
i + 1, (unsigned int)fr_dlist_num_elements(&sc->workers));
- SEM_WAIT_INTR(&sc->worker_sem);
+ SEM_WAIT_INTR(sc->worker_sem);
}
/*
for (i = 0; i < (unsigned int)fr_dlist_num_elements(&sc->networks); i++) {
DEBUG2("Scheduler - Waiting for semaphore indicating network exit %u/%u", i + 1,
(unsigned int)fr_dlist_num_elements(&sc->networks));
- SEM_WAIT_INTR(&sc->network_sem);
+ SEM_WAIT_INTR(sc->network_sem);
}
DEBUG2("Scheduler - All networks indicated exit complete");
for (i = 0; i < (unsigned int)fr_dlist_num_elements(&sc->workers); i++) {
DEBUG2("Scheduler - Waiting for semaphore indicating worker exit %u/%u", i + 1,
(unsigned int)fr_dlist_num_elements(&sc->workers));
- SEM_WAIT_INTR(&sc->worker_sem);
+ SEM_WAIT_INTR(sc->worker_sem);
}
DEBUG2("Scheduler - All workers indicated exit complete");
}
}
- sem_destroy(&sc->network_sem);
- sem_destroy(&sc->worker_sem);
+ fr_sem_free(sc->network_sem);
+ fr_sem_free(sc->worker_sem);
done:
/*
* Now that all of the workers are done, we can return to
--- /dev/null
+/*
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/** API for POSIX semaphores in mmapped memory.
+ *
+ * @file src/lib/util/semaphore.c
+ *
+ * @copyright 2025 Network RADIUS SAS (legal@networkradius.com)
+ */
+RCSID("$Id$")
+
+#include <sys/mman.h>
+#include <freeradius-devel/util/semaphore.h>
+#include <freeradius-devel/util/strerror.h>
+#include <freeradius-devel/util/syserror.h>
+
+fr_sem_t *fr_sem_alloc(void)
+{
+ fr_sem_t *sem;
+
+ sem = mmap(NULL, sizeof(fr_sem_t), PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
+
+ if (sem == MAP_FAILED) {
+ fr_strerror_printf("Failed allocating mmap memory: %s", fr_syserror(errno));
+ return NULL;
+ }
+
+ if (sem_init(sem, 1, SEMAPHORE_LOCKED) != 0) {
+ sem_destroy(sem);
+ munmap(sem, sizeof(fr_sem_t));
+ return NULL;
+ }
+
+ return sem;
+}
+
+void fr_sem_free(fr_sem_t *sem)
+{
+ if (!sem) return;
+
+ sem_destroy(sem);
+ munmap(sem, sizeof(fr_sem_t));
+}
--- /dev/null
+#pragma once
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/** API for POSIX semaphores in mmapped memory.
+ *
+ * @file src/lib/util/semaphore.h
+ *
+ * @copyright 2025 Network RADIUS SAS (legal@networkradius.com)
+ */
+RCSIDH(semaphore_h, "$Id$")
+
+#include <freeradius-devel/util/talloc.h>
+
+/*
+ * Other OS's have sem_init, OS X doesn't.
+ */
+#ifdef HAVE_SEMAPHORE_H
+#include <semaphore.h>
+#endif
+
+#define SEMAPHORE_LOCKED (0)
+
+#ifdef __APPLE__
+#include <mach/task.h>
+#include <mach/mach_init.h>
+#include <mach/semaphore.h>
+
+typedef semaphore_t fr_sem_t;
+#undef sem_init
+#define sem_init(s,p,c) semaphore_create(mach_task_self(),s,SYNC_POLICY_FIFO,c)
+#undef sem_wait
+#define sem_wait(s) semaphore_wait(*s)
+#undef sem_post
+#define sem_post(s) semaphore_signal(*s)
+#undef sem_destroy
+#define sem_destroy(s) semaphore_destroy(mach_task_self(),*s)
+#else
+typedef sem_t fr_sem_t;
+#endif /* __APPLE__ */
+
+#define SEM_WAIT_INTR(_x) do {if (sem_wait(_x) == 0) break;} while (errno == EINTR)
+
+fr_sem_t *fr_sem_alloc(void);
+
+void fr_sem_free(fr_sem_t *sem);