Switch to a simple X11-style license.
[polintos/scott/priv.git] / kernel / core / lock.cc
1 // core/thread.cc -- Scheduler and thread creation/destruction
2 //
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
4 // 
5 // Permission is hereby granted, free of charge, to any person obtaining a copy of
6 // this software and associated documentation files (the "Software"), to deal with
7 // the Software without restriction, including without limitation the rights to
8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 // of the Software, and to permit persons to whom the Software is furnished to do
10 // so, subject to the following condition:
11 // 
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 // 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
21 // SOFTWARE.
22
23 #include <util/lock.h>
24 #include <kern/thread.h>
25
26 namespace Lock {
27         // OPT: add inline, lockless uncontended case
28
29         // FIXME: Allow a high-priority blocker to steal a lock from
30         // a low-priority holder if the holder has not yet run.  This
31         // prevents rescheduling every iteration if both threads are
32         // repeatedly acquiring and releasing the lock.
33         
34         void Lock::lock()
35         {
36                 DroppableAutoSpinLockRecIRQ autolock(spinlock);
37                 
38                 if (!lockval) {
39                         lockval = reinterpret_cast<ulong>(curthread);
40                         return;
41                 }
42                 
43                 assert(lockval != reinterpret_cast<ulong>(curthread));
44                 
45                 Threads::ThreadBlocker blocker(curthread);
46                 waitqueue.block(&blocker);
47                 
48                 if (!lockval) {
49                         lockval = reinterpret_cast<ulong>(curthread);
50                         waitqueue.unblock(&blocker);
51                         return;
52                 }
53                 
54                 autolock.unlock();
55                 curthread->block(&blocker);
56                 
57                 // FIXME: interruptible locks
58                 assert(lockval == reinterpret_cast<ulong>(curthread));
59         }
60         
61         void Lock::unlock()
62         {
63                 AutoSpinLockRecIRQ autolock(spinlock);
64                 assert(lockval == reinterpret_cast<ulong>(curthread));
65                 
66                 if (waitqueue.empty()) {
67                         lockval = 0;
68                         return;
69                 }
70                 
71                 Threads::Blocker *b = waitqueue.unblock_one();
72                 lockval = reinterpret_cast<ulong>(b->thread);
73                 b->wake();
74         }
75 }