]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Use mmapped memory for POSIX semaphores
authorNick Porter <nick@portercomputing.co.uk>
Tue, 18 Nov 2025 08:57:09 +0000 (08:57 +0000)
committerNick Porter <nick@portercomputing.co.uk>
Fri, 13 Mar 2026 09:55:48 +0000 (09:55 +0000)
In preparation for using separate processes in place of threads

src/lib/io/schedule.c
src/lib/util/libfreeradius-util.mk
src/lib/util/semaphore.c [new file with mode: 0644]
src/lib/util/semaphore.h [new file with mode: 0644]

index 6f8469b3cb6dff550e4282871cd3437f2c469257..592f3b66630caa9a77dbe6c90ef234131c390a69 100644 (file)
@@ -33,37 +33,10 @@ RCSID("$Id$")
 #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.
  */
@@ -135,8 +108,8 @@ struct fr_schedule_s {
 
        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;
@@ -262,7 +235,7 @@ static void *fr_schedule_worker_thread(void *arg)
        /*
         *      Tell the originator that the thread has started.
         */
-       sem_post(&sc->worker_sem);
+       sem_post(sc->worker_sem);
 
        /*
         *      Do all of the work.
@@ -293,7 +266,7 @@ fail:
        /*
         *      Tell the scheduler we're done.
         */
-       sem_post(&sc->worker_sem);
+       sem_post(sc->worker_sem);
 
        talloc_free(ctx);
 
@@ -378,7 +351,7 @@ static void *fr_schedule_network_thread(void *arg)
        /*
         *      Tell the originator that the thread has started.
         */
-       sem_post(&sc->network_sem);
+       sem_post(sc->network_sem);
 
        DEBUG3("%s - Started", network_name);
 
@@ -405,7 +378,7 @@ fail:
        /*
         *      Tell the scheduler we're done.
         */
-       sem_post(&sc->network_sem);
+       sem_post(sc->network_sem);
 
        talloc_free(ctx);
 
@@ -589,20 +562,17 @@ fr_schedule_t *fr_schedule_create(TALLOC_CTX *ctx, fr_event_list_t *el,
        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.
@@ -640,7 +610,7 @@ fr_schedule_t *fr_schedule_create(TALLOC_CTX *ctx, fr_event_list_t *el,
        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);
        }
 
        /*
@@ -701,7 +671,7 @@ fr_schedule_t *fr_schedule_create(TALLOC_CTX *ctx, fr_event_list_t *el,
        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);
        }
 
        /*
@@ -820,7 +790,7 @@ int fr_schedule_destroy(fr_schedule_t **sc_to_free)
        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");
 
@@ -848,7 +818,7 @@ int fr_schedule_destroy(fr_schedule_t **sc_to_free)
        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");
 
@@ -871,8 +841,8 @@ int fr_schedule_destroy(fr_schedule_t **sc_to_free)
                }
        }
 
-       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
index f7d7fc149412bc4c22cd8833c111bb9868ee1549..e3723deddfc4509c7157e05cc8a7e079392be46d 100644 (file)
@@ -79,6 +79,7 @@ SOURCES               := \
                   retry.c \
                   sbuff.c \
                   sem.c \
+                  semaphore.c \
                   sha1.c \
                   size.c \
                   skip.c \
diff --git a/src/lib/util/semaphore.c b/src/lib/util/semaphore.c
new file mode 100644 (file)
index 0000000..a390513
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *   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));
+}
diff --git a/src/lib/util/semaphore.h b/src/lib/util/semaphore.h
new file mode 100644 (file)
index 0000000..64ef309
--- /dev/null
@@ -0,0 +1,60 @@
+#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);