SEMA(9)

πŸ“¦ version 15.1, in freebsd 14.5, freebsd 15.1, nixpkgs unstable

πŸŽ€ SEMA(9) β€” kernel counting semaphore πŸŽ€

okay so this is a page from the Kernel Developer's Manual, and it's all about sema and friends. bestie, if you've ever needed to hand out a limited number of things to a bunch of threads without anyone throwing hands, this is the page. let's go πŸ’…


✨ NAME ✨

sema, sema_init, sema_destroy, sema_post, sema_wait, sema_timedwait, sema_trywait, sema_value β€” the kernel's counting semaphore situation 🧚


🌸 SYNOPSIS 🌸

first, you gotta bring in the headers, no cap:

#include <sys/types.h>
#include <sys/lock.h>
#include <sys/sema.h>

and then the whole cast of characters:

void
sema_init(struct sema *sema, int value, const char *description);

void
sema_destroy(struct sema *sema);

void
sema_post(struct sema *sema);

void
sema_wait(struct sema *sema);

int
sema_timedwait(struct sema *sema, int timo);

int
sema_trywait(struct sema *sema);

int
sema_value(struct sema *sema);

πŸ’– DESCRIPTION πŸ’–

okay so counting semaphores are literally a mechanism for synchronizing access to a pool of resources. think of it like a bouncer at a club with a limited capacity 🫢

and here's the iconic difference: unlike mutexes, semaphores do not have the concept of an owner. which means they're also useful when one thread needs to acquire a resource and another thread needs to release it. the way that just works 😭

each semaphore has an integer value chillin' with it. posting (incrementing) always succeeds β€” no questions asked. but waiting (decrementing) can only successfully complete if the resulting value of the semaphore is greater than or equal to zero. so like, >= 0 or it's a no from me πŸ’€

real talk: semaphores should not be used where mutexes and condition variables will suffice. semaphores are a more complex synchronization mechanism than mutexes and condition variables, and are not as efficient. like, they're giving main character energy but they're not the move in every situation, ngl.

so here's the whole lifecycle, step by step:

  • you create semaphores with sema_init(), where:
    • sema is a pointer to space for a struct sema
    • value is the initial value of the semaphore
    • description is a pointer to a null-terminated character string that describes the semaphore
  • you destroy them with sema_destroy() ⭐
  • you post (increment) with sema_post() πŸ”₯
  • you wait on (decrement) with sema_wait(), sema_timedwait(), or sema_trywait()
  • and the timo argument to sema_timedwait() specifies the minimum time in ticks to wait before returning with failure ⏰
  • sema_value() is used to read the current value of the semaphore πŸ‘‘

🌈 RETURN VALUES 🌈

sema_value() returns the current value of the semaphore. simple as that ✨

now for the spicy ones:

  • if decrementing the semaphore would result in its value being negative, sema_trywait() returns 0 to indicate failure. otherwise, a non-zero value is returned to indicate success. so yeah, 0 = sad, non-zero = slay πŸ’…
  • sema_timedwait() returns 0 if waiting on the semaphore succeeded; otherwise a non-zero error code is returned πŸŽ€

πŸ¦‹ ERRORS πŸ¦‹

sema_timedwait() will fail if:

  • [EWOULDBLOCK] β€” Timeout expired. that's it, that's the whole list, your time ran out bestie πŸ™ˆ

πŸ‘‘ SEE ALSO πŸ‘‘

condvar(9), locking(9), mtx_pool(9), mutex(9), rwlock(9), sx(9) β€” go read these too, iykyk 🌸


and that's the page fr fr πŸ’œ this little gem comes to you from Debian, dated February 1, 2006 β€” yes she's an elder but she still eats. periodt. πŸŽ€βœ¨

πŸ“¦ where this page comes from