Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
[sfrench/cifs-2.6.git] / arch / mn10300 / kernel / semaphore.c
1 /* MN10300 Semaphore implementation
2  *
3  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public Licence
8  * as published by the Free Software Foundation; either version
9  * 2 of the Licence, or (at your option) any later version.
10  */
11 #include <linux/sched.h>
12 #include <linux/module.h>
13 #include <asm/semaphore.h>
14
15 struct sem_waiter {
16         struct list_head        list;
17         struct task_struct      *task;
18 };
19
20 #if SEMAPHORE_DEBUG
21 void semtrace(struct semaphore *sem, const char *str)
22 {
23         if (sem->debug)
24                 printk(KERN_DEBUG "[%d] %s({%d,%d})\n",
25                        current->pid,
26                        str,
27                        atomic_read(&sem->count),
28                        list_empty(&sem->wait_list) ? 0 : 1);
29 }
30 #else
31 #define semtrace(SEM, STR) do { } while (0)
32 #endif
33
34 /*
35  * wait for a token to be granted from a semaphore
36  * - entered with lock held and interrupts disabled
37  */
38 void __down(struct semaphore *sem, unsigned long flags)
39 {
40         struct task_struct *tsk = current;
41         struct sem_waiter waiter;
42
43         semtrace(sem, "Entering __down");
44
45         /* set up my own style of waitqueue */
46         waiter.task = tsk;
47         get_task_struct(tsk);
48
49         list_add_tail(&waiter.list, &sem->wait_list);
50
51         /* we don't need to touch the semaphore struct anymore */
52         spin_unlock_irqrestore(&sem->wait_lock, flags);
53
54         /* wait to be given the semaphore */
55         set_task_state(tsk, TASK_UNINTERRUPTIBLE);
56
57         for (;;) {
58                 if (!waiter.task)
59                         break;
60                 schedule();
61                 set_task_state(tsk, TASK_UNINTERRUPTIBLE);
62         }
63
64         tsk->state = TASK_RUNNING;
65         semtrace(sem, "Leaving __down");
66 }
67 EXPORT_SYMBOL(__down);
68
69 /*
70  * interruptibly wait for a token to be granted from a semaphore
71  * - entered with lock held and interrupts disabled
72  */
73 int __down_interruptible(struct semaphore *sem, unsigned long flags)
74 {
75         struct task_struct *tsk = current;
76         struct sem_waiter waiter;
77         int ret;
78
79         semtrace(sem, "Entering __down_interruptible");
80
81         /* set up my own style of waitqueue */
82         waiter.task = tsk;
83         get_task_struct(tsk);
84
85         list_add_tail(&waiter.list, &sem->wait_list);
86
87         /* we don't need to touch the semaphore struct anymore */
88         set_task_state(tsk, TASK_INTERRUPTIBLE);
89
90         spin_unlock_irqrestore(&sem->wait_lock, flags);
91
92         /* wait to be given the semaphore */
93         ret = 0;
94         for (;;) {
95                 if (!waiter.task)
96                         break;
97                 if (unlikely(signal_pending(current)))
98                         goto interrupted;
99                 schedule();
100                 set_task_state(tsk, TASK_INTERRUPTIBLE);
101         }
102
103  out:
104         tsk->state = TASK_RUNNING;
105         semtrace(sem, "Leaving __down_interruptible");
106         return ret;
107
108  interrupted:
109         spin_lock_irqsave(&sem->wait_lock, flags);
110         list_del(&waiter.list);
111         spin_unlock_irqrestore(&sem->wait_lock, flags);
112
113         ret = 0;
114         if (!waiter.task) {
115                 put_task_struct(current);
116                 ret = -EINTR;
117         }
118         goto out;
119 }
120 EXPORT_SYMBOL(__down_interruptible);
121
122 /*
123  * release a single token back to a semaphore
124  * - entered with lock held and interrupts disabled
125  */
126 void __up(struct semaphore *sem)
127 {
128         struct task_struct *tsk;
129         struct sem_waiter *waiter;
130
131         semtrace(sem, "Entering __up");
132
133         /* grant the token to the process at the front of the queue */
134         waiter = list_entry(sem->wait_list.next, struct sem_waiter, list);
135
136         /* We must be careful not to touch 'waiter' after we set ->task = NULL.
137          * It is an allocated on the waiter's stack and may become invalid at
138          * any time after that point (due to a wakeup from another source).
139          */
140         list_del_init(&waiter->list);
141         tsk = waiter->task;
142         smp_mb();
143         waiter->task = NULL;
144         wake_up_process(tsk);
145         put_task_struct(tsk);
146
147         semtrace(sem, "Leaving __up");
148 }
149 EXPORT_SYMBOL(__up);