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

Last change on this file since 8 was 1, checked in by alain, 8 years ago

First import

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 <almos_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        uint32_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                if( taken == 0 )
61        {
62            // try to take the lock if not already taken
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    // enable interrupts if irq_state == NULL
72        if( irq_state ) *irq_state = mode;
73        else            hal_restore_irq( mode );
74}
75
76//////////////////////////////////////////////
77void spinlock_unlock_busy( spinlock_t * lock,
78                           bool_t       restore, 
79                           uint32_t     irq_state )
80{
81        thread_t * this = CURRENT_THREAD;;
82 
83    lock->owner = NULL;
84    lock->taken = 0;
85    this->local_locks--;
86    list_unlink( &lock->list );
87 
88        if( restore ) hal_restore_irq( irq_state );
89}
90   
91///////////////////////////////////////
92void spinlock_lock( spinlock_t * lock )
93{
94        uint32_t          mode;
95        thread_t        * this     = CURRENT_THREAD;
96        bool_t            isAtomic = false;
97        volatile uint32_t taken;
98   
99    // disable interrupts
100        hal_disable_irq( &mode );
101 
102    // loop until success
103        while( isAtomic == false )
104        {
105        taken = lock->taken;
106
107        // deschedule without blocking when lock already taken
108                if( taken != 0 )
109        {
110            hal_restore_irq( mode );
111            if( thread_can_yield() ) sched_yield();
112            hal_disable_irq( &mode );
113            continue;
114        }
115
116        // try to atomically take the lock if not already taken
117            isAtomic = hal_atomic_cas( &lock->taken , 0 , 1 );
118    }
119
120        this->local_locks++;
121    lock->owner = this;
122    list_add_first( &this->locks_root , &lock->list );
123
124    // enable interrupts
125    hal_restore_irq( mode );
126}
127
128//////////////////////////////////////////////
129uint32_t spinlock_trylock( spinlock_t * lock )
130{ 
131        uint32_t   mode;
132        bool_t     isAtomic = false;
133        thread_t * this     = CURRENT_THREAD;
134
135        hal_disable_irq( &mode );
136
137        if( lock->taken == 0)
138                isAtomic = hal_atomic_cas( &lock->taken , 0 , 1);
139 
140        if(isAtomic == false)
141        {
142                hal_restore_irq(mode);
143                return 1;
144        }
145    else
146    {
147            this->local_locks++;
148            lock->owner = this;
149        list_add_first( &this->locks_root , &lock->list );
150            hal_restore_irq(mode); 
151            return 0;
152    }
153}
154
155/////////////////////////////////////////
156void spinlock_unlock( spinlock_t * lock )
157{
158        thread_t * this = CURRENT_THREAD;
159 
160    lock->owner = NULL;
161    lock->taken = 0;
162    this->local_locks--;
163    list_unlink( &lock->list );
164}
165
166
Note: See TracBrowser for help on using the repository browser.