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

Last change on this file since 540 was 540, checked in by nicolas.van.phan@…, 3 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
Line 
1/*
2 * spinlock.c - kernel spinlock synchronization
3 *
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
25#include <kernel_config.h>
26#include <hal_kernel_types.h>
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 )
37{
38    lock->taken = 0;
39
40#if DEBUG_SPINLOCKS
41lock->owner = NULL;
42list_entry_init( &lock->list );
43#endif
44
45}
46
47///////////////////////////////////////////
48void spinlock_lock_busy( spinlock_t * lock,
49                         reg_t      * irq_state )
50{
51    reg_t               mode;
52    volatile uint32_t   taken;
53    thread_t          * this     = CURRENT_THREAD;
54    bool_t              isAtomic = false;
55
56    // disable interrupts
57    hal_disable_irq( &mode );
58
59    // loop until success
60    while( isAtomic == false )
61    {
62        taken = lock->taken;
63
64        // try to take the lock if not already taken
65        if( taken == 0 )
66        {
67            isAtomic = hal_atomic_cas( &lock->taken , 0 , 1 );
68        }
69    }
70
71    this->local_locks++;
72
73#if DEBUG_SPINLOCKS
74lock->owner = this;
75list_add_first( &this->locks_root , &lock->list );
76#endif
77
78    // irq_state must be restored when lock is released
79    *irq_state = mode;
80}
81
82//////////////////////////////////////////////
83void spinlock_unlock_busy( spinlock_t * lock,
84                           reg_t        irq_state )
85{
86    thread_t * this = CURRENT_THREAD;
87
88#if DEBUG_SPINLOCKS
89lock->owner = NULL;
90list_unlink( &lock->list );
91#endif
92
93    hal_fence();
94    lock->taken = 0;
95    this->local_locks--;
96
97    // deschedule if pending request
98    thread_check_sched();
99 
100    // restore IRQs
101        hal_restore_irq( irq_state );
102}
103
104///////////////////////////////////////
105void spinlock_lock( spinlock_t * lock )
106{
107    reg_t             mode;
108    thread_t        * this     = CURRENT_THREAD;
109    bool_t            isAtomic = false;
110    volatile uint32_t taken;
111
112    // disable interrupts
113    hal_disable_irq( &mode );
114
115    // loop until success
116    while( isAtomic == false )
117    {
118        taken = lock->taken;
119
120        // deschedule without blocking when lock already taken
121        if( taken != 0 )
122        {
123            hal_restore_irq( mode );
124            if( thread_can_yield() ) sched_yield("waiting spinlock");
125            hal_disable_irq( &mode );
126            continue;
127        }
128
129        // try to atomically take the lock if not already taken
130        isAtomic = hal_atomic_cas( &lock->taken , 0 , 1 );
131    }
132
133    this->local_locks++;
134
135#if DEBUG_SPINLOCKS
136lock->owner = this;
137list_add_first( &this->locks_root , &lock->list );
138#endif
139
140    // restore IRQs
141    hal_restore_irq( mode );
142}
143
144/////////////////////////////////////////////
145error_t spinlock_trylock( spinlock_t * lock )
146{
147    reg_t      mode;
148    bool_t     isAtomic = false;
149    thread_t * this     = CURRENT_THREAD;
150
151    hal_disable_irq( &mode );
152
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    }
161    else
162    {
163        this->local_locks++;
164
165#if DEBUG_SPINLOCKS
166lock->owner = this;
167list_add_first( &this->locks_root , &lock->list );
168#endif
169
170        hal_restore_irq(mode);
171        return 0;
172    }
173}
174
175/////////////////////////////////////////
176void spinlock_unlock( spinlock_t * lock )
177{
178    thread_t * this = CURRENT_THREAD;
179
180#if DEBUG_SPINLOCKS
181lock->owner = NULL;
182list_unlink( &lock->list );
183#endif
184    hal_fence();
185    lock->taken = 0;
186    this->local_locks--;
187
188    // deschedule if pending request
189    thread_check_sched();
190}
191
Note: See TracBrowser for help on using the repository browser.