📄 sem.c
字号:
int rt_cond_wait_timed(CND *cnd, SEM *mtx, RTIME delay){ return rt_cond_wait_until(cnd, mtx, get_time() + delay);}/* ++++++++++++++++++++ READERS-WRITER LOCKS SUPPORT ++++++++++++++++++++++++ *//** * @anchor rt_rwl_init * @brief Initialize a multi readers single writer lock. * * rt_rwl_init initializes a multi readers single writer lock @rwl. * * @param rwl must point to an allocated @e RWL structure. * * A multi readers single writer lock (RWL) is a synchronization mechanism * that allows to have simultaneous read only access to an object, while only * one task can have write access. A data set which is searched more * frequently than it is changed can be usefully controlled by using an rwl. * The lock acquisition policy is determined solely on the priority of tasks * applying to own a lock. * * @returns 0 if always. * */int rt_rwl_init(RWL *rwl){ rt_typed_sem_init(&rwl->wrmtx, 1, RES_SEM); rt_typed_sem_init(&rwl->wrsem, 0, CNT_SEM); rt_typed_sem_init(&rwl->rdsem, 0, CNT_SEM); return 0;}/** * @anchor rt_rwl_delete * @brief destroys a multi readers single writer lock. * * rt_rwl_init destroys a multi readers single writer lock @rwl. * * @param rwl must point to an allocated @e RWL structure. * * @returns 0 if OK, SEM_ERR if anything went wrong. * */int rt_rwl_delete(RWL *rwl){ int ret; ret = rt_sem_delete(&rwl->rdsem); ret |= !rt_sem_delete(&rwl->wrsem); ret |= !rt_sem_delete(&rwl->wrmtx); return ret ? 0 : SEM_ERR;}/** * @anchor rt_rwl_rdlock * @brief acquires a multi readers single writer lock for reading. * * rt_rwl_rdlock acquires a multi readers single writer lock @rwl for * reading. The calling task will block only if any writer owns the lock * already or there are writers with higher priority waiting to acquire * write access. * * @param rwl must point to an allocated @e RWL structure. * * @returns 0 if OK, SEM_ERR if anything went wrong after being blocked. * */int rt_rwl_rdlock(RWL *rwl){ unsigned long flags; RT_TASK *wtask, *rt_current; flags = rt_global_save_flags_and_cli(); rt_current = RT_CURRENT; while (rwl->wrmtx.owndby || ((wtask = (rwl->wrsem.queue.next)->task) && wtask->priority <= rt_current->priority)) { int ret; if (rwl->wrmtx.owndby == rt_current) { rt_global_restore_flags(flags); return SEM_ERR + 1; } if ((ret = rt_sem_wait(&rwl->rdsem)) >= SEM_TIMOUT) { rt_global_restore_flags(flags); return ret; } } ((int *)&rwl->rdsem.owndby)[0]++; rt_global_restore_flags(flags); return 0;}/** * @anchor rt_rwl_rdlock_if * @brief try to acquire a multi readers single writer lock just for reading. * * rt_rwl_rdlock_if tries to acquire a multi readers single writer lock @rwl * for reading immediately, i.e. without blocking if a writer owns the lock * or there are writers with higher priority waiting to acquire write access. * * @param rwl must point to an allocated @e RWL structure. * * @returns 0 if the lock was acquired, -1 if the lock was already owned. * */int rt_rwl_rdlock_if(RWL *rwl){ unsigned long flags; RT_TASK *wtask; flags = rt_global_save_flags_and_cli(); if (!rwl->wrmtx.owndby && (!(wtask = (rwl->wrsem.queue.next)->task) || wtask->priority > RT_CURRENT->priority)) { ((int *)&rwl->rdsem.owndby)[0]++; rt_global_restore_flags(flags); return 0; } rt_global_restore_flags(flags); return -1;}/** * @anchor rt_rwl_rdlock_until * @brief try to acquire a multi readers single writer lock for reading within * an absolute deadline time. * * rt_rwl_rdlock_untill tries to acquire a multi readers single writer lock * @rwl for reading, as for rt_rwl_rdlock, but timing out if the lock has not * been acquired within an assigned deadline. * * @param rwl must point to an allocated @e RWL structure. * * @time is the time deadline, in internal count units. * * @returns 0 if the lock was acquired, SEM_TIMOUT if the deadline expired * without acquiring the lock, SEM_ERR in case something went wrong. * */int rt_rwl_rdlock_until(RWL *rwl, RTIME time){ unsigned long flags; RT_TASK *wtask, *rt_current; flags = rt_global_save_flags_and_cli(); rt_current = RT_CURRENT; while (rwl->wrmtx.owndby || ((wtask = (rwl->wrsem.queue.next)->task) && wtask->priority <= rt_current->priority)) { int ret; if (rwl->wrmtx.owndby == rt_current) { rt_global_restore_flags(flags); return SEM_ERR + 1; } if ((ret = rt_sem_wait_until(&rwl->rdsem, time)) >= SEM_TIMOUT) { rt_global_restore_flags(flags); return ret; } } ((int *)&rwl->rdsem.owndby)[0]++; rt_global_restore_flags(flags); return 0;}/** * @anchor rt_rwl_rdlock_timed * @brief try to acquire a multi readers single writer lock for reading within * a relative deadline time. * * rt_rwl_rdlock_timed tries to acquire a multi readers single writer lock @rwl * for reading, as for rt_rwl_rdlock, but timing out if the lock has not been * acquired within an assigned deadline. * * @param rwl must point to an allocated @e RWL structure. * * @delay is the time delay within which the lock must be acquired, in * internal count units. * * @returns 0 if the lock was acquired, SEM_TIMOUT if the deadline expired * without acquiring the lock, SEM_ERR in case something went wrong. * */int rt_rwl_rdlock_timed(RWL *rwl, RTIME delay){ return rt_rwl_rdlock_until(rwl, get_time() + delay);}/** * @anchor rt_rwl_wrlock * @brief acquires a multi readers single writer lock for wrtiting. * * rt_rwl_rwlock acquires a multi readers single writer lock @rwl for * writing. The calling task will block if any other task, reader or writer, * owns the lock already. * * @param rwl must point to an allocated @e RWL structure. * * @returns 0 if OK, SEM_ERR if anything went wrong after being blocked. * */int rt_rwl_wrlock(RWL *rwl){ unsigned long flags; int ret; flags = rt_global_save_flags_and_cli(); while (rwl->rdsem.owndby) { if ((ret = rt_sem_wait(&rwl->wrsem)) >= SEM_TIMOUT) { rt_global_restore_flags(flags); return ret; } } if ((ret = rt_sem_wait(&rwl->wrmtx)) >= SEM_TIMOUT) { rt_global_restore_flags(flags); return ret; } rt_global_restore_flags(flags); return 0;}/** * @anchor rt_rwl_wrlock_if * @brief acquires a multi readers single writer lock for writing. * * rt_rwl_wrlock_if try to acquire a multi readers single writer lock @rwl * for writing immediately, i.e without blocking if the lock is owned already. * * @param rwl must point to an allocated @e RWL structure. * * @returns 0 if the lock was acquired, -1 if the lock was already owned. * */int rt_rwl_wrlock_if(RWL *rwl){ unsigned long flags; flags = rt_global_save_flags_and_cli(); if (!rwl->rdsem.owndby && rt_sem_wait_if(&rwl->wrmtx) >= 0) { rt_global_restore_flags(flags); return 0; } rt_global_restore_flags(flags); return -1;}/** * @anchor rt_rwl_wrlock_until * @brief try to acquire a multi readers single writer lock for writing within * an absolute deadline time. * * rt_rwl_rwlock_until tries to acquire a multi readers single writer lock * @rwl for writing, as for rt_rwl_rwlock, but timing out if the lock has not * been acquired within an assigned deadline. * * @param rwl must point to an allocated @e RWL structure. * * @time is the time deadline, in internal count units. * * @returns 0 if the lock was acquired, SEM_TIMOUT if the deadline expired * without acquiring the lock, SEM_ERR in case something went wrong. * */int rt_rwl_wrlock_until(RWL *rwl, RTIME time){ unsigned long flags; int ret; flags = rt_global_save_flags_and_cli(); while (rwl->rdsem.owndby) { if ((ret = rt_sem_wait_until(&rwl->wrsem, time)) >= SEM_TIMOUT) { rt_global_restore_flags(flags); return ret; }; } if ((ret = rt_sem_wait_until(&rwl->wrmtx, time)) >= SEM_TIMOUT) { rt_global_restore_flags(flags); return ret; }; rt_global_restore_flags(flags); return 0;}/** * @anchor rt_rwl_wrlock_timed * @brief try to acquire a multi readers single writer lock for writing within * a relative deadline time. * * rt_rwl_wrlock_timed tries to acquire a multi readers single writer lock @rwl * for writing, as for rt_rwl_wrlock, timing out if the lock has not been * acquired within an assigned deadline. * * @param rwl must point to an allocated @e RWL structure. * * @delay is the time delay within which the lock must be acquired, in * internal count units. * * @returns 0 if the lock was acquired, SEM_TIMOUT if the deadline expired * without acquiring the lock, SEM_ERR in case something went wrong. * */int rt_rwl_wrlock_timed(RWL *rwl, RTIME delay){ return rt_rwl_wrlock_until(rwl, get_time() + delay);}/** * @anchor rt_rwl_unlock * @brief unlock an acquired multi readers single writer lock. * * rt_rwl_unlock unlocks an acquired multi readers single writer lock @rwl. * After releasing the lock any task waiting to acquire it will own the lock * according to its priority, whether it is a reader or a writer, otherwise * the lock will be fully unlocked. * * @param rwl must point to an allocated @e RWL structure. * * @returns 0 always. * */int rt_rwl_unlock(RWL *rwl){ unsigned long flags; flags = rt_global_save_flags_and_cli(); if (rwl->wrmtx.owndby) { rt_sem_signal(&rwl->wrmtx); } else if (rwl->rdsem.owndby) { rwl->rdsem.owndby = (struct rt_task_struct *)((char *)rwl->rdsem.owndby - 1); } rt_global_restore_flags(flags); flags = rt_global_save_flags_and_cli(); if (!rwl->wrmtx.owndby && !rwl->rdsem.owndby) { RT_TASK *wtask, *rtask; wtask = (rwl->wrsem.queue.next)->task; rtask = (rwl->rdsem.queue.next)->task; if (wtask && rtask) { if (wtask->priority < rtask->priority) { rt_sem_signal(&rwl->wrsem); } else { rt_sem_signal(&rwl->rdsem); } } else if (wtask) { rt_sem_signal(&rwl->wrsem); } else if (rtask) { rt_sem_signal(&rwl->rdsem); } } rt_global_restore_flags(flags); return 0;}/* +++++++++++++++++++++ RECURSIVE SPINLOCKS SUPPORT ++++++++++++++++++++++++ *//** * @anchor rt_spl_init * @brief Initialize a spinlock. * * rt_spl_init initializes a spinlock @spl. * * @param spl must point to an allocated @e SPL structure. * * A spinlock is an active wait synchronization mechanism useful for multi * processors very short synchronization, when it is more efficient to wait * at a meeting point instead of being suspended and the reactivated, as by * using semaphores, to acquire ownership of any object. * Spinlocks can be recursed once acquired, a recurring owner must care of * unlocking as many times as he took the spinlock. * * @returns 0 if always. * */int rt_spl_init(SPL *spl){ spl->owndby = 0; spl->count = 0; return 0;}/** * @anchor rt_spl_delete * @brief Initialize a spinlock. * * rt_spl_delete destroies a spinlock @spl. * * @param spl must point to an allocated @e SPL structure. * * @returns 0 if always. * */int rt_spl_delete(SPL *spl){ return 0;}/** * @anchor rt_spl_lock * @brief Acquire a spinlock. * * rt_spl_lock acquires a spinlock @spl. * * @param spl must point to an allocated @e SPL structure. * * rt_spl_lock spins on lock till it can be acquired. If a tasks asks for * lock it owns already it will acquire it immediately but will have to care * to unlock it as many times as it recursed the spinlock ownership. * * @returns 0 if always. * */int rt_spl_lock(SPL *spl){ unsigned long flags; RT_TASK *rt_current; hard_save_flags_and_cli(flags); if (spl->owndby == (rt_current = RT_CURRENT)) { spl->count++; } else { while (atomic_cmpxchg(&spl->owndby, 0, rt_current)); spl->flags = flags; } return 0;}/** * @anchor rt_spl_lock_if * @brief Acquire a spinlock without waiting. * * rt_spl_lock_if acquires a spinlock @spl without waiting. * * @param spl must point to an allocated @e SPL structure. * * rt_spl_lock_if tries to acquire a spinlock but will not spin on it if * it is owned already. * * @returns 0 if it succeeded, -1 if the lock was owned already. * */int rt_spl_lock_if(SPL *spl){ unsigned long flags; RT_TASK *rt_current; hard_save_flags_and_cli(flags);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -