////////////////////////////////////////////////////////////////////////////////// // File : spin_lock.c // Date : 01/04/2012 // Author : alain greiner // Copyright (c) UPMC-LIP6 /////////////////////////////////////////////////////////////////////////////////// // The spin_lock.c and spin_lock.h files are part of the GIET nano-kernel. // This middlewre implements a user-level lock (busy waiting mechanism, // because the GIET does not support task scheduling / descheduling). // It is a simple binary lock, without waiting queue. // // The lock_acquire(), lock_try_acquire() and lock_release() functions do // not require a system call. // // ALL locks must be defined in the mapping_info data structure, // to be initialised by the GIET in the boot phase. // The vobj_get_vbase() system call (defined in stdio.c and stdio.h files) // can be used to get the virtual base address of the lock from it's name. /////////////////////////////////////////////////////////////////////////////////// #include #include /////////////////////////////////////////////////////////////////////////////////// // lock_acquire() // This blocking function returns only when the lock has been taken. // If the lock is already taken a random delay is introduced before retry. /////////////////////////////////////////////////////////////////////////////////// void lock_acquire( giet_lock_t* lock ) { unsigned int* plock = &lock->value; asm volatile ( "giet_lock_try: \n" "ll $2, 0(%0) \n" /* $2 <= lock current value */ "bnez $2, giet_lock_delay \n" /* retry if lock already taken */ "li $3, 1 \n" /* $3 <= argument for sc */ "sc $3, 0(%0) \n" /* try to get lock */ "bnez $3, giet_lock_ok \n" /* exit if atomic */ "giet_lock_delay: \n" "jal giet_rand \n" /* giet_rand() system call */ "nop \n" "andi $4, $2, 0xFF \n" /* $4 <= delay < 256 cycles */ "giet_lock_loop: \n" "addi $4, $4, -1 \n" /* $4 <= $4 - 1 */ "beqz $4, giet_lock_loop \n" /* test end delay */ "nop \n" "j giet_lock_try \n" /* retry */ "nop \n" "giet_lock_ok: \n" : :"r"(plock) :"$2", "$3", "$4"); } ////////////////////////////////////////////////////////////////////////////// // lock_release() ////////////////////////////////////////////////////////////////////////////// void lock_release( giet_lock_t* lock) { lock->value = 0; } ////////////////////////////////////////////////////////////////////////////// // lock_try_acquire() ////////////////////////////////////////////////////////////////////////////// int lock_try_acquire( giet_lock_t* lock ) { register int ret = 0; register unsigned int* plock = &lock->value; asm volatile ("ll $2, 0(%1) \n" // $2 <= _locks_lock "bnez $2, _lock_done \n" // exitif busy "li $3, 1 \n" // prepare argument for sc "sc $3, 0(%1) \n" // try to set _locks_busy "xori %0, $3, 1 \n" // ret = !$3 "_lock_done: \n" :"=r"(ret) :"r"(plock) :"$2","$3"); return ret; }