1/*
2 * Copyright (c) 2007, 2008, 2009, 2011, 2012, ETH Zurich.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#include <lwip/sys.h>
11#include <barrelfish/barrelfish.h>
12#include <barrelfish/deferred.h>
13#include <barrelfish/systime.h>
14
15/*
16 * TODO:
17 * - implement timeout versions of semaphores and mailboxes correctly
18 * - implement mboxes of size > 1
19 * - implement sys_msleep
20 * - implement sys_jiffies
21 */
22
23unsigned char debug_flags;
24
25u32_t sys_now(void)
26{
27    uint64_t ns = systime_to_ns(systime_now());
28    return ns / 1000000;
29}
30
31#if 0
32
33// from example in http://lwip.wikia.com/wiki/Porting_for_an_OS
34struct thread_wrapper {
35  struct thread_wrapper *next;
36  struct thread *thread;  // barrelfish thread
37  struct sys_timeouts timeouts;
38};
39
40
41// track threads and timeouts.
42struct sys_timeouts lwip_system_timeouts = { .next = NULL }; // Default timeouts list for lwIP
43struct thread_wrapper *lwip_system_threads = NULL; // a list of all threads created by lwIP
44
45
46// wrapper for a condition variable with timeout
47static u32_t thread_cond_wait_timeout(struct thread_cond *cond,
48                                      struct thread_mutex *mutex,
49                                      u32_t timeout)
50{
51    // TODO: implement timeout properly
52    thread_cond_wait(cond, mutex);
53    return timeout;
54}
55
56
57static void *last_locker = NULL, *last_user = NULL;
58struct thread_mutex *lwip_mutex;
59
60void lwip_mutex_lock(void)
61{
62    if (lwip_mutex != NULL) {
63      	last_locker = __builtin_return_address(0);
64        thread_mutex_lock(lwip_mutex);
65    }
66}
67
68void lwip_mutex_unlock(void)
69{
70    if (lwip_mutex != NULL) {
71    	if(lwip_mutex->locked == 0) {
72			printf("mutex NOT locked, called %p, last %p, locked by %p\n", __builtin_return_address(0), last_user, last_locker);
73      	} else {
74			last_user = __builtin_return_address(0);
75      	}
76       	 thread_mutex_unlock(lwip_mutex);
77    }
78}
79
80
81#if SYS_LIGHTWEIGHT_PROT
82static struct thread_mutex lock = THREAD_MUTEX_INITIALIZER;
83
84sys_prot_t sys_arch_protect(void)
85{
86    thread_mutex_lock(&lock);
87    return 0;
88}
89
90void sys_arch_unprotect(sys_prot_t pval)
91{
92    // this is always true (sys_prot_t is uint8_t!) -AB
93    //if(pval >= 0) {
94        thread_mutex_unlock(&lock);
95    //}
96}
97
98#endif // SYS_LIGHTWEIGHT_PROT
99
100/* sys_init() must be called before anthing else. */
101void sys_init(void)
102{
103    // Nothing to do
104}
105
106
107
108// from example in http://lwip.wikia.com/wiki/Porting_for_an_OS
109struct sys_timeouts *sys_arch_timeouts(void) {
110    struct thread_wrapper *thread = lwip_system_threads;
111    struct thread *self = thread_self(); // current thread
112
113    // Search the threads list for the thread that is currently running
114    for ( ; thread != NULL; thread = thread->next) {
115        if (thread->thread == self) {
116            return &thread->timeouts;
117        }
118    }
119
120    // No match, so just return the system-wide default version
121    return &lwip_system_timeouts;
122}
123
124
125
126/* Semaphore functions. */
127sys_sem_t sys_sem_new(u8_t count)
128{
129    /* debug_printf("sys_sem_new(%d)\n", count); */
130    struct thread_sem *newsem = malloc(sizeof(struct thread_sem));
131    thread_sem_init(newsem, count);
132    return newsem;
133}
134
135void sys_sem_signal(sys_sem_t sem)
136{
137    /* printf("sys_sem_signal\n"); */
138    thread_sem_post(sem);
139}
140
141u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)
142{
143    // TODO: implement timeout correctly
144
145    /* printf("sys_arch_sem_wait\n"); */
146
147    systime_t start, end;
148    start = get_system_time();
149
150    thread_sem_wait(sem);
151
152    end = get_system_time();
153
154    return end - start;
155}
156
157void sys_sem_free(sys_sem_t sem)
158{
159    free(sem);
160}
161
162
163
164
165
166u32_t sys_jiffies(void)
167{
168    /* since power up. */
169    assert(!"NYI");
170    return 0;
171}
172
173/* Mailbox functions. */
174sys_mbox_t sys_mbox_new(int size)
175{
176    // TODO: support mailboxes of size > 1. we only support size 1 right now
177
178    // debug_printf("sys_mbox_new(%d)\n", size);
179
180    sys_mbox_t mbox;
181    mbox = (sys_mbox_t)malloc(sizeof(struct bf_sys_mbox));
182
183    if (mbox == NULL) {
184        return SYS_MBOX_NULL;
185    }
186    mbox->msg = NULL;
187    mbox->empty = true;
188
189    thread_mutex_init(&mbox->mutex);
190    thread_cond_init(&mbox->changed_cond);
191
192//    debug_printf("sys_mbox_new(%p): created of size %d\n", mbox, size);
193    return mbox;
194}
195
196void sys_mbox_post(sys_mbox_t mbox, void *msg)
197{
198//    debug_printf("sys_mbox_post(%p)\n", mbox);
199
200    // keep trying until we succeed
201    while (1) {
202        thread_mutex_lock(&mbox->mutex);
203        if (mbox->empty) {
204            mbox->msg = msg;
205            mbox->empty = false;
206            thread_mutex_unlock(&mbox->mutex);
207            thread_cond_signal(&mbox->changed_cond);
208            break;
209        } else {
210            // wait until something changes
211            thread_cond_wait(&mbox->changed_cond, &mbox->mutex);
212            thread_mutex_unlock(&mbox->mutex);
213        }
214    }
215
216//    debug_printf("sys_mbox_post(%p) done\n", mbox);
217}
218
219err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg)
220{
221//    debug_printf("sys_mboxtry_post(%p)\n", mbox);
222
223    err_t err;
224    thread_mutex_lock(&mbox->mutex);
225    if (mbox->empty) {
226        mbox->msg = msg;
227        mbox->empty = false;
228        thread_cond_signal(&mbox->changed_cond);
229        err = ERR_OK;
230    } else {
231        err = ERR_MEM;
232    }
233    thread_mutex_unlock(&mbox->mutex);
234
235    return err;
236}
237
238u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)
239{
240//    debug_printf("sys_arch_mbox_fetch(%p) timeout %u\n",mbox, timeout);
241
242    u32_t time_left = timeout;
243    u32_t res;
244
245    systime_t start, end;
246    start = get_system_time();
247
248    // keep trying until we succeed
249    while (1) {
250        if (time_left <= 0 && timeout != 0) {
251            return SYS_ARCH_TIMEOUT;
252        }
253        thread_mutex_lock(&mbox->mutex);
254        if (!mbox->empty) {
255            if (msg != NULL) {
256                *msg = mbox->msg;
257            }
258            mbox->empty = true;
259            thread_mutex_unlock(&mbox->mutex);
260            thread_cond_signal(&mbox->changed_cond);
261            break;
262        } else {
263            // wait until something changes
264            if (timeout != 0) {
265                time_left -= thread_cond_wait_timeout(&mbox->changed_cond,
266                                                      &mbox->mutex,
267                                                      time_left);
268            } else {
269                thread_cond_wait(&mbox->changed_cond, &mbox->mutex);
270            }
271            thread_mutex_unlock(&mbox->mutex);
272        }
273    }
274
275    end = get_system_time();
276
277    if (timeout == 0) {
278        res = end - start;
279    } else {
280        res = timeout - time_left;
281    }
282
283//    debug_printf("sys_arch_mbox_fetch(%p) done!\n", mbox);
284    return res;
285}
286
287u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg)
288{
289    //    assert(!"NYI");
290    u32_t res;
291    thread_mutex_lock(&mbox->mutex);
292    if (!mbox->empty) {
293        *msg = mbox->msg;
294        mbox->empty = true;
295        thread_cond_signal(&mbox->changed_cond);
296        res = 0; // success
297    } else {
298        res = SYS_MBOX_EMPTY;
299    }
300    thread_mutex_unlock(&mbox->mutex);
301
302    return res;
303}
304
305void sys_mbox_free(sys_mbox_t mbox)
306{
307    assert(mbox != NULL);
308    assert(mbox->empty);
309    free(mbox);
310}
311
312// from example in http://lwip.wikia.com/wiki/Porting_for_an_OS
313sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg),
314                            void *arg, int stacksize, int prio)
315{
316    sys_thread_t newthread;
317    SYS_ARCH_DECL_PROTECT(old_val);
318
319//    debug_printf("sys_thread_new(%s, %p, %p)\n", name, thread, arg);
320
321    // TODO: this has to get free'd when the thread terminates
322    newthread = (sys_thread_t)malloc(sizeof(struct thread_wrapper));
323    if (newthread == NULL) {
324        return NULL;
325    }
326
327    // Need to protect this -- preemption here could be a problem!
328    SYS_ARCH_PROTECT(old_val);
329    newthread->next = lwip_system_threads;
330    lwip_system_threads = newthread;
331    SYS_ARCH_UNPROTECT(old_val);
332
333    newthread->timeouts.next = NULL; // initialize the linked list to NULL
334
335    // TODO: do something with the rest of the arguments (name, stacksize, prio)
336    newthread->thread = thread_create((thread_func_t)thread, arg);
337    if (newthread->thread == NULL) {
338        SYS_ARCH_PROTECT(old_val);
339        lwip_system_threads = newthread->next;
340        SYS_ARCH_UNPROTECT(old_val);
341        free(newthread);
342        newthread = NULL;
343    }
344
345    return newthread;
346}
347#endif
348