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

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

use reg_t instead of uint32_t

File size: 3.9 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();
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
164
Note: See TracBrowser for help on using the repository browser.