source: trunk/kernel/libk/spinlock.c @ 542

Last change on this file since 542 was 540, checked in by nicolas.van.phan@…, 6 years ago

TTY MUX 5/5 : Multiplex TTY character receiving

The multiplexing for receving chars is done by redirecting
the IRQs (when a char is received) to the right chdev (so the right
server DEV thread). When the user types an uppercase letter,
it is treated as a special char used to change the active tty
by redirecting the IRQs to the chdev corresponding to the appropriate
channel.

Add some documentation and example in the code.

Add mfences calls in spinlock_unlock_busy fix a bug on letty physical
hardware.

File size: 4.4 KB
RevLine 
[1]1/*
2 * spinlock.c - kernel spinlock synchronization
[331]3 *
[1]4 * Authors   Ghassan Almaless  (2008,2009,2010,2011,2012)
5 *           Alain Greiner     (2016}
6 *
7 * Copyright (c) UPMC Sorbonne Universites
8 *
9 * This file is part of ALMOS-MKH.
10 *
11 * ALMOS-MKH is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2.0 of the License.
14 *
15 * ALMOS-MKH is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
[14]25#include <kernel_config.h>
[457]26#include <hal_kernel_types.h>
[1]27#include <hal_atomic.h>
28#include <hal_special.h>
29#include <hal_irqmask.h>
30#include <thread.h>
31#include <scheduler.h>
32#include <printk.h>
33#include <spinlock.h>
34
35//////////////////////////////////////////////
36inline void spinlock_init( spinlock_t * lock )
[331]37{
38    lock->taken = 0;
[409]39
[438]40#if DEBUG_SPINLOCKS
[436]41lock->owner = NULL;
42list_entry_init( &lock->list );
[409]43#endif
44
[1]45}
46
47///////////////////////////////////////////
[331]48void spinlock_lock_busy( spinlock_t * lock,
[473]49                         reg_t      * irq_state )
[1]50{
[331]51    reg_t               mode;
52    volatile uint32_t   taken;
53    thread_t          * this     = CURRENT_THREAD;
54    bool_t              isAtomic = false;
[1]55
56    // disable interrupts
[331]57    hal_disable_irq( &mode );
58
[1]59    // loop until success
[331]60    while( isAtomic == false )
61    {
62        taken = lock->taken;
[1]63
[11]64        // try to take the lock if not already taken
[331]65        if( taken == 0 )
[1]66        {
[331]67            isAtomic = hal_atomic_cas( &lock->taken , 0 , 1 );
[1]68        }
[331]69    }
[1]70
[331]71    this->local_locks++;
[409]72
[438]73#if DEBUG_SPINLOCKS
[436]74lock->owner = this;
75list_add_first( &this->locks_root , &lock->list );
[409]76#endif
[1]77
[331]78    // irq_state must be restored when lock is released
[11]79    *irq_state = mode;
[1]80}
81
82//////////////////////////////////////////////
83void spinlock_unlock_busy( spinlock_t * lock,
[473]84                           reg_t        irq_state )
[1]85{
[461]86    thread_t * this = CURRENT_THREAD;
[331]87
[438]88#if DEBUG_SPINLOCKS
[436]89lock->owner = NULL;
90list_unlink( &lock->list );
[409]91#endif
92
[540]93    hal_fence();
[1]94    lock->taken = 0;
95    this->local_locks--;
[331]96
[337]97    // deschedule if pending request
98    thread_check_sched();
99 
100    // restore IRQs
101        hal_restore_irq( irq_state );
[1]102}
[331]103
[1]104///////////////////////////////////////
105void spinlock_lock( spinlock_t * lock )
106{
[331]107    reg_t             mode;
108    thread_t        * this     = CURRENT_THREAD;
109    bool_t            isAtomic = false;
110    volatile uint32_t taken;
111
[1]112    // disable interrupts
[331]113    hal_disable_irq( &mode );
114
[1]115    // loop until success
[331]116    while( isAtomic == false )
117    {
[1]118        taken = lock->taken;
119
120        // deschedule without blocking when lock already taken
[331]121        if( taken != 0 )
[1]122        {
123            hal_restore_irq( mode );
[408]124            if( thread_can_yield() ) sched_yield("waiting spinlock");
[1]125            hal_disable_irq( &mode );
126            continue;
127        }
128
129        // try to atomically take the lock if not already taken
[331]130        isAtomic = hal_atomic_cas( &lock->taken , 0 , 1 );
[1]131    }
132
[331]133    this->local_locks++;
[409]134
[438]135#if DEBUG_SPINLOCKS
[436]136lock->owner = this;
137list_add_first( &this->locks_root , &lock->list );
[409]138#endif
[1]139
[337]140    // restore IRQs
[1]141    hal_restore_irq( mode );
142}
143
[11]144/////////////////////////////////////////////
145error_t spinlock_trylock( spinlock_t * lock )
[331]146{
147    reg_t      mode;
148    bool_t     isAtomic = false;
149    thread_t * this     = CURRENT_THREAD;
[1]150
[331]151    hal_disable_irq( &mode );
[1]152
[331]153    if( lock->taken == 0)
154        isAtomic = hal_atomic_cas( &lock->taken , 0 , 1);
155
156    if(isAtomic == false)
157    {
158        hal_restore_irq(mode);
159        return 1;
160    }
[1]161    else
162    {
[331]163        this->local_locks++;
[409]164
[438]165#if DEBUG_SPINLOCKS
[436]166lock->owner = this;
167list_add_first( &this->locks_root , &lock->list );
[409]168#endif
169
[331]170        hal_restore_irq(mode);
171        return 0;
[1]172    }
173}
174
175/////////////////////////////////////////
176void spinlock_unlock( spinlock_t * lock )
177{
[331]178    thread_t * this = CURRENT_THREAD;
179
[438]180#if DEBUG_SPINLOCKS
[436]181lock->owner = NULL;
182list_unlink( &lock->list );
[409]183#endif
[540]184    hal_fence();
[1]185    lock->taken = 0;
186    this->local_locks--;
[337]187
188    // deschedule if pending request
189    thread_check_sched();
[1]190}
191
Note: See TracBrowser for help on using the repository browser.