/* Copyright (C) 2021,2022 fef . All rights reserved. */ #pragma once #include #include struct task; typedef struct { atom_t lock; /* 0 = free, 1 = locked */ } spin_t; #define SPIN_DEFINE { \ .lock = ATOM_DEFINE(0), \ } #define SPIN(name) struct spin name = SPIN_DEFINE void spin_init(spin_t *spin); void spin_lock(spin_t *spin); bool spin_trylock(spin_t *spin); void spin_unlock(spin_t *spin); struct lock_waiter { struct clist clink; struct task *task; }; /** * @brief Yielding mutual exclusion lock. * * Several rules apply when using a mutex: * * - No access from irq context or within a critical section * - Must be unlocked from the same thread that locked it * - No more than one consecutive unlock allowed */ struct mtx { atom_t lock; /* 1 = free, 0 = locked, < 0 = locked and other threads are waiting */ spin_t wait_queue_lock; struct clist wait_queue; /* -> struct lock_waiter::clink */ }; #define MTX_DEFINE(name) { \ .lock = ATOM_DEFINE(1), \ .wait_queue_lock = SPIN_DEFINE, \ .wait_queue = CLIST_DEFINE((name).wait_queue), \ } #define MTX(name) struct mtx name = MTX_DEFINE(name) void mtx_init(struct mtx *mutex); void mtx_lock(struct mtx *mutex); void mtx_unlock(struct mtx *mutex); bool mtx_trylock(struct mtx *mutex); struct sem { atom_t count; spin_t wait_queue_lock; struct clist wait_queue; /* -> struct lock_waiter::clink */ }; #define SEM_DEFINE(name, initial_count) { \ .count = ATOM_DEFINE(initial_count), \ .wait_queue_lock = SPIN_DEFINE, \ .wait_queue = CLIST_DEFINE((name).wait_queue), \ } #define SEM(name, initial_count) \ struct sem name = SEM_DEFINE(name, initial_count) void sem_init(struct sem *sem, int initial_count); int sem_down(struct sem *semaphore); int sem_up(struct sem *semaphore); int sem_trydown(struct sem *semaphore);