---
title: "Semaphores"
canonical_url: https://developer.repebble.com/pebbleos/docs/samples/kernel/semaphore/
last_updated: 2026-11-13
sdk_version: 4.44
---
# Semaphores

Source: https://developer.repebble.com/pebbleos/docs/samples/kernel/semaphore/

This sample uses a semaphore in its two roles. As a signal, an interrupt (a timer callback here) tells a waiting thread that a transfer is done, and the thread gives up if it is not told in time. As a counter, it lets four workers share two channels.

A give from an interrupt never blocks. The second transfer times out, and stops the timer so a late interrupt cannot signal the next one.

Run:

`pbl samples samples/kernel/semaphore`

Boards:

every board

## Sources

src/main.c

```
#include \<errno.h\>#include \<pbl/kernel/delay.h\>#include \<pbl/kernel/mutex.h\>#include \<pbl/kernel/sem.h\>#include \<pbl/kernel/thread.h\>#include \<pbl/kernel/timer.h\>#include \<pbl/logging/logging.h\>#include \<pbl/util/size.h\>#define NUM\_WORKERS 4#define NUM\_CHANNELS 2/\* Binary: an interrupt tells a thread that what it waits for has happened. \*/static PBL\_SEM\_DEFINE(s\_transfer\_done, 0, 1);/\* Counting: as many tokens as there are channels to share. \*/static PBL\_SEM\_DEFINE(s\_channels, NUM\_CHANNELS, NUM\_CHANNELS);static PBL\_MUTEX\_DEFINE(s\_stats\_lock);static unsigned int s\_busy\_channels;static unsigned int s\_max\_busy\_channels;PBL\_THREAD\_STACK\_DEFINE(s\_stack\_0, 1024);PBL\_THREAD\_STACK\_DEFINE(s\_stack\_1, 1024);PBL\_THREAD\_STACK\_DEFINE(s\_stack\_2, 1024);PBL\_THREAD\_STACK\_DEFINE(s\_stack\_3, 1024);static struct pbl\_thread s\_workers[NUM\_WORKERS];/\* Runs in the tick interrupt, standing for the one of a peripheral. \*/static void prv\_transfer\_isr(struct pbl\_timer \*timer) {pbl\_sem\_give(&s\_transfer\_done);}static struct pbl\_timer s\_transfer\_timer = PBL\_TIMER\_INITIALIZER(prv\_transfer\_isr);static int prv\_transfer(uint32\_t duration\_ms) {pbl\_timer\_start(&s\_transfer\_timer, PBL\_MSEC(duration\_ms));if (pbl\_sem\_take(&s\_transfer\_done, PBL\_MSEC(100)) != 0) {pbl\_timer\_stop(&s\_transfer\_timer);return -ETIMEDOUT;}return 0;}static void prv\_worker(void \*arg) {pbl\_sem\_take(&s\_channels, PBL\_FOREVER);pbl\_mutex\_lock(&s\_stats\_lock, PBL\_FOREVER);s\_busy\_channels++;if (s\_busy\_channels \> s\_max\_busy\_channels) {s\_max\_busy\_channels = s\_busy\_channels;}pbl\_mutex\_unlock(&s\_stats\_lock);pbl\_sleep\_ms(20);pbl\_mutex\_lock(&s\_stats\_lock, PBL\_FOREVER);s\_busy\_channels--;pbl\_mutex\_unlock(&s\_stats\_lock);pbl\_sem\_give(&s\_channels);}int main(void) {void \*const stacks[NUM\_WORKERS] = {s\_stack\_0, s\_stack\_1, s\_stack\_2, s\_stack\_3};int ret;ret = prv\_transfer(10);PBL\_LOG\_INFO("main: 10 ms transfer returns %d", ret);ret = prv\_transfer(5000);PBL\_LOG\_INFO("main: 5 s transfer returns %s", ret == -ETIMEDOUT ? "-ETIMEDOUT" : "other");for (unsigned int i = 0; i \< NUM\_WORKERS; i++) {const struct pbl\_thread\_attr attr = {.name = "worker",.entry = prv\_worker,.prio = CONFIG\_KERNEL\_MAIN\_THREAD\_PRIO - 1,.privileged = true,.stack = stacks[i],.stack\_size = sizeof(s\_stack\_0),};pbl\_thread\_create(&s\_workers[i], &attr);}for (unsigned int i = 0; i \< NUM\_WORKERS; i++) {ret = PBL\_POLL\_SLEEP\_MS(pbl\_thread\_state(&s\_workers[i]) == PBL\_THREAD\_DEAD, 1, 1000);if (ret != 0) {PBL\_LOG\_ERR("main: worker %u did not end (%d)", i, ret);return ret;}}PBL\_LOG\_INFO("main: %u workers shared %u channels, at most %u busy at once", NUM\_WORKERS,NUM\_CHANNELS, s\_max\_busy\_channels);PBL\_LOG\_INFO("main: %u channels free again", (unsigned int)pbl\_sem\_count(&s\_channels));PBL\_LOG\_INFO("Sample done");return 0;}
```

## Output

```
main: 10 ms transfer returns 0
main: 5 s transfer returns -ETIMEDOUT
main: 4 workers shared 2 channels, at most 2 busy at once
main: 2 channels free again
Sample done
```

Generated from PebbleOS [f4926c952](https://github.com/coredevices/pebbleos/commit/f4926c952bf9b82bce9e3cdb44645a59531c0ee9). This page is maintained in the pebbleos repository: [docs/samples/kernel/semaphore.md](https://github.com/coredevices/pebbleos/blob/f4926c952bf9b82bce9e3cdb44645a59531c0ee9/docs/samples/kernel/semaphore.md).
