/* * spinlock.h: kernel spinlock definition * * Authors Alain Greiner (2016,2017,2018) * * Copyright (c) UPMC Sorbonne Universites * * This file is part of ALMOS-MKH. * * ALMOS-MKH 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; version 2.0 of the License. * * ALMOS-MKH 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 ALMOS-kernel; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SPINLOCK_H_ #define _SPINLOCK_H_ #include #include #include /******************************************************************************************* * This structure defines a local spinlock, that sequencializes all read or write accesses * in a given cluster. A new access can only start after completion of the previous access, * when the owner thread releases the lock. The lock has only two states: taken or free. * The owner thread is registered in the spinlock_t structure, and the calling thread * list of local spinlocks is updated. * * A spinlock can be accessed in three modes : * * - The spinlock_lock() function is BLOCKING and use a descheduling policy when the lock * is already taken. The lock must be released with the spinlock_unlock() function. * - The spinlock_lock_noirq() function is BLOCKING, but uses a polling (busy-waiting) * policy if the lock is already taken. The IRQs can be disabled or not depending * on the irq_state argument. The lock must be released with the spinlock_unlock_noirq() * function. * - The spinlock_trylock() function is NON-BLOCKING, and tries only once to take the lock. * It must be released with the spinlock_unlock() function. ******************************************************************************************/ /**** Forward declarations ****/ struct thread_s; /******************************************************************************************* * This structure defines a local spinlock. * The "owner" and "list" are optionnal fields used for debug. * It register the list of all spinlocks taken by a given thread. ******************************************************************************************/ typedef struct spinlock_s { uint32_t taken; /*! state : free if zero / taken if non zero */ #if DEBUG_SPINLOCKS struct thread_s * owner; /*! pointer on curent owner thread */ list_entry_t list; /*! member of list of locks taken by owner */ #endif } spinlock_t; /******************************************************************************************* * This function initializes a local spinlock in free state. ******************************************************************************************* * @ lock : pointer on spinlock. ******************************************************************************************/ inline void spinlock_init( spinlock_t * lock ); /******************************************************************************************* * This blocking function uses a busy waiting strategy to lock a local spinlock. * It polls the lock and returns only when the lock has been taken. * All IRQs are disabled and will keep disabled until the lock is released. * It increments the calling thread local_locks count when the lock has been taken. ******************************************************************************************* * @ lock : pointer on spinlock * @ irq_state : buffer to save the SR state (in the calling thread stack) ******************************************************************************************/ void spinlock_lock_busy( spinlock_t * lock, uint32_t * irq_state ); /******************************************************************************************* * This function releases a local busy_waiting spinlock. * It restores the CPU SR state. ******************************************************************************************* * @ lock : pointer on spinlock * @ irq_state : value to be resrored in CPU SR ******************************************************************************************/ void spinlock_unlock_busy( spinlock_t * lock, uint32_t irq_state ); /******************************************************************************************* * This blocking function locks a local spinlock. * If the lock is already taken, the calling thread deschedules without blocking, * and retries when it is rescheduled, until success. * It increments the calling thread local_locks count when the lock has been taken. ******************************************************************************************* * @ lock : pointer on spinlock ******************************************************************************************/ void spinlock_lock( spinlock_t * lock ); /******************************************************************************************* * This non-blocking function tries once to lock a spinlock. * It increments the calling thread locks count in case of success. ******************************************************************************************* * @ lock : pointer on spinlock * @ returns 0 if success / returns non zero if lock already taken. ******************************************************************************************/ error_t spinlock_trylock( spinlock_t * lock ); /******************************************************************************************* * This function releases a spinlock and do schedule if necessary. ******************************************************************************************* * @ lock : pointer on spinlock ******************************************************************************************/ void spinlock_unlock( spinlock_t * lock ); #endif /* _SPINLOCK_H_ */