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

Last change on this file since 334 was 331, checked in by max@…, 7 years ago

style

File size: 4.1 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_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    lock->owner = NULL;
40    list_entry_init( &lock->list );
41}
42
43///////////////////////////////////////////
44void spinlock_lock_busy( spinlock_t * lock,
45                         uint32_t   * irq_state )
46{
47    reg_t               mode;
48    volatile uint32_t   taken;
49    thread_t          * this     = CURRENT_THREAD;
50    bool_t              isAtomic = false;
51
52    // disable interrupts
53    hal_disable_irq( &mode );
54
55    // loop until success
56    while( isAtomic == false )
57    {
58        taken = lock->taken;
59
60        // try to take the lock if not already taken
61        if( taken == 0 )
62        {
63            isAtomic = hal_atomic_cas( &lock->taken , 0 , 1 );
64        }
65    }
66
67    this->local_locks++;
68    lock->owner = this;
69    list_add_first( &this->locks_root , &lock->list );
70
71    // irq_state must be restored when lock is released
72    *irq_state = mode;
73}
74
75//////////////////////////////////////////////
76void spinlock_unlock_busy( spinlock_t * lock,
77                           uint32_t     irq_state )
78{
79    thread_t * this = CURRENT_THREAD;;
80
81    lock->owner = NULL;
82    lock->taken = 0;
83    this->local_locks--;
84    list_unlink( &lock->list );
85
86    hal_restore_irq( irq_state );
87}
88
89///////////////////////////////////////
90void spinlock_lock( spinlock_t * lock )
91{
92    reg_t             mode;
93    thread_t        * this     = CURRENT_THREAD;
94    bool_t            isAtomic = false;
95    volatile uint32_t taken;
96
97    // disable interrupts
98    hal_disable_irq( &mode );
99
100    // loop until success
101    while( isAtomic == false )
102    {
103        taken = lock->taken;
104
105        // deschedule without blocking when lock already taken
106        if( taken != 0 )
107        {
108            hal_restore_irq( mode );
109            if( thread_can_yield() ) sched_yield( NULL );
110            hal_disable_irq( &mode );
111            continue;
112        }
113
114        // try to atomically take the lock if not already taken
115        isAtomic = hal_atomic_cas( &lock->taken , 0 , 1 );
116    }
117
118    this->local_locks++;
119    lock->owner = this;
120    list_add_first( &this->locks_root , &lock->list );
121
122    // enable interrupts
123    hal_restore_irq( mode );
124}
125
126/////////////////////////////////////////////
127error_t spinlock_trylock( spinlock_t * lock )
128{
129    reg_t      mode;
130    bool_t     isAtomic = false;
131    thread_t * this     = CURRENT_THREAD;
132
133    hal_disable_irq( &mode );
134
135    if( lock->taken == 0)
136        isAtomic = hal_atomic_cas( &lock->taken , 0 , 1);
137
138    if(isAtomic == false)
139    {
140        hal_restore_irq(mode);
141        return 1;
142    }
143    else
144    {
145        this->local_locks++;
146        lock->owner = this;
147        list_add_first( &this->locks_root , &lock->list );
148        hal_restore_irq(mode);
149        return 0;
150    }
151}
152
153/////////////////////////////////////////
154void spinlock_unlock( spinlock_t * lock )
155{
156    thread_t * this = CURRENT_THREAD;
157
158    lock->owner = NULL;
159    lock->taken = 0;
160    this->local_locks--;
161    list_unlink( &lock->list );
162}
163
Note: See TracBrowser for help on using the repository browser.