]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/input/lib/src/emul_wait.c
66f95caa6e26d6e8a2e26fdadd2f7722f4b9a94f
[l4.git] / l4 / pkg / input / lib / src / emul_wait.c
1 /*****************************************************************************/
2 /**
3  * \file   input/lib/src/emul_wait
4  * \brief  L4INPUT: Linux Wait queue emulation
5  *
6  * \date   2005/05/24
7  * \author Frank Mehnert <fm3@os.inf.tu-dresden.de>
8  *
9  * I've no idea if this is really needed.
10  */
11 /*
12  * (c) 2005-2009 Technische Universität Dresden
13  * This file is part of TUD:OS and distributed under the terms of the
14  * GNU General Public License 2.
15  * Please see the COPYING-GPL-2 file for details.
16  */
17
18 #include <stdio.h>
19 #include <l4/sys/ipc.h>
20 #include <l4/util/util.h>
21 #include <l4/util/l4_macros.h>
22 #include <linux/wait.h>
23 #include <linux/jiffies.h>
24
25 #include <pthread.h>
26 #include <pthread-l4.h>
27
28 l4_cap_idx_t wait_thread;
29
30 //#define dbg(format...) printf(format)
31 #define dbg(format...)
32
33 /** Enqueue entry into list. */
34 static void
35 enqueue_entry(wait_queue_head_t *wqh, wait_queue_entry_t *e)
36 {
37   if (!wqh->first)
38     wqh->first = e;
39   else
40     {
41       wait_queue_entry_t *w;
42       for (w=wqh->first; w->next; w=w->next)
43         ;
44       w->next = e;
45     }
46 }
47
48 /** Enqueue list into main list. */
49 static void
50 enqueue_head(wait_queue_head_t **wqm, wait_queue_head_t *h)
51 {
52   if (!*wqm)
53     *wqm = h;
54   else
55     {
56       wait_queue_head_t *w = *wqm;
57       for (;;)
58         {
59           if (w == h)
60             return;
61           if (!w->next)
62             {
63               w->next = h;
64               return;
65             }
66           w = w->next;
67         }
68     }
69 }
70
71 /** Dequeue list from main list. */
72 static void
73 dequeue_head(wait_queue_head_t **wqm, wait_queue_head_t *h)
74 {
75   for (; *wqm; *wqm=(*wqm)->next)
76     {
77       if (*wqm == h)
78         {
79           *wqm = h->next;
80           return;
81         }
82     }
83 }
84
85 /** Wakeup all threads enqueued in list. */
86 static void
87 wakeup(wait_queue_head_t *h)
88 {
89   wait_queue_entry_t *e;
90   l4_cap_idx_t tid;
91   l4_umword_t dummy;
92
93   for (e=h->first; e;)
94     {
95       dbg("    wakeup entry %p\n", e);
96       dbg("      ("l4util_idfmt", next=%p)\n", 
97           l4util_idstr(e->tid), e->next);
98       tid = e->tid;
99       e   = e->next;
100
101       l4_ipc(tid, l4_utcb(), L4_SYSF_SEND, pthread_getl4cap(pthread_self()),
102              l4_msgtag(0, 0, 0, 0), &dummy, L4_IPC_NEVER);
103     }
104   h->first = 0;
105 }
106
107 /** The waiter thread. */
108 static void *
109 __wait_thread(void *ignore)
110 {
111   l4_cap_idx_t src;
112   l4_umword_t dw1, dw2;
113   l4_umword_t dummy;
114   l4_msgtag_t r;
115   l4_timeout_t to = l4_timeout(L4_IPC_TIMEOUT_NEVER,
116                                l4util_micros2l4to(10000));
117   int error;
118   wait_queue_head_t *main_queue = 0;
119
120   //l4thread_started(NULL);
121
122   for (;;)
123     {
124       r = l4_ipc_wait(l4_utcb(), &src, main_queue ? to : L4_IPC_NEVER);
125       dw1 = l4_utcb_mr()->mr[0];
126       dw2 = l4_utcb_mr()->mr[1];
127
128       error = l4_ipc_error(r, l4_utcb());
129
130       if (error == 0)
131         {
132           /* got request */
133           if (dw1 != 0)
134             {
135               /* go sleep, append at wait queue */
136               wait_queue_head_t  *h = (wait_queue_head_t*)dw1;
137               wait_queue_entry_t *e = (wait_queue_entry_t*)dw2;
138
139               dbg("enqueue "l4util_idfmt" into queue %p entry %p\n", l4util_idstr(src), (void*)dw1, (void*)dw2);
140
141               e->tid  = src;
142               e->next = 0;
143
144               /* append entry to wait queue */
145               enqueue_entry(h, e);
146               /* append wait queue to main queue if necessary */
147               enqueue_head(&main_queue, h);
148
149               dbg("  queue now ");
150               for (e=h->first; e; e=e->next)
151                 dbg("%p ", e);
152               dbg("\n");
153             }
154           else
155             {
156               /* wakeup */
157               wait_queue_head_t *h = ((wait_queue_head_t*)dw2);
158               dbg("wakeup queue %p\n", (void*)dw2);
159               /* wakeup waiting threads of wait queue */
160               wakeup(h);
161               /* dequeue wait queue from main queue */
162               dequeue_head(&main_queue, h);
163               dbg("  main=%p\n", (void*)main_queue);
164               l4_ipc(src, l4_utcb(), L4_SYSF_SEND,
165                      pthread_getl4cap(pthread_self()),
166                      l4_msgtag(0, 0, 0, 0), &dummy, L4_IPC_NEVER);
167             }
168         }
169       else if (error == L4_IPC_RETIMEOUT)
170         {
171           /* timeout, wakeup all queues */
172           wait_queue_head_t *h;
173           dbg("wakup all queues\n");
174           for (h=main_queue; h; h=h->next)
175             {
176               dbg("  wakeup queue %p\n", h);
177               wakeup(h);
178             }
179           main_queue = 0;
180         }
181       else
182         {
183           /* ??? */
184         }
185     }
186   return NULL;
187 }
188
189 /** Called if a specific wait queue should be woken up. */
190 void
191 wake_up(wait_queue_head_t *wq)
192 {
193   l4_umword_t dummy;
194
195   l4_utcb_mr()->mr[0] = 0;
196   l4_utcb_mr()->mr[1] = (l4_umword_t)(wq);
197   l4_ipc(wait_thread, l4_utcb(), L4_SYSF_CALL,
198          pthread_getl4cap(pthread_self()),
199          l4_msgtag(0, 2, 0, 0),
200          &dummy, L4_IPC_NEVER);
201 }
202
203 /** Initialization. */
204 void
205 l4input_internal_wait_init(void)
206 {
207   pthread_t t;
208   pthread_attr_t a;
209   struct sched_param sp;
210
211   pthread_attr_init(&a);
212   sp.sched_priority = 255;
213   pthread_attr_setschedpolicy(&a, SCHED_L4);
214   pthread_attr_setschedparam(&a, &sp);
215   pthread_attr_setinheritsched(&a, PTHREAD_EXPLICIT_SCHED);
216
217   if (pthread_create(&t, &a, __wait_thread, NULL))
218     return;
219
220   wait_thread = pthread_getl4cap(t);
221
222   pthread_attr_destroy(&a);
223 }