Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Add updated lwip files in src/lwip
[palacios.git] / palacios / src / lwip / arch / sys_arch.c
1 /*
2  * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
3  * All rights reserved. 
4  * 
5  * Redistribution and use in source and binary forms, with or without modification, 
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission. 
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
19  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
21  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
24  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
25  * OF SUCH DAMAGE.
26  *
27  * This file is part of the lwIP TCP/IP stack.
28  * 
29  * Author: Adam Dunkels <adam@sics.se>
30  *
31  */
32
33 /*
34  * Wed Apr 17 16:05:29 EDT 2002 (James Roth)
35  *
36  *  - Fixed an unlikely sys_thread_new() race condition.
37  *
38  *  - Made current_thread() work with threads which where
39  *    not created with sys_thread_new().  This includes
40  *    the main thread and threads made with pthread_create().
41  *
42  *  - Catch overflows where more than SYS_MBOX_SIZE messages
43  *    are waiting to be read.  The sys_mbox_post() routine
44  *    will block until there is more room instead of just
45  *    leaking messages.
46  */
47 #include "lwip/debug.h"
48
49 #include <string.h>
50 #include <sys/time.h>
51 #include <sys/types.h>
52 #include <stdlib.h>
53 #include <unistd.h>
54 #include <pthread.h>
55
56 #include "lwip/sys.h"
57 #include "lwip/opt.h"
58 #include "lwip/stats.h"
59
60 #define UMAX(a, b)      ((a) > (b) ? (a) : (b))
61
62 static struct sys_thread *threads = NULL;
63 static pthread_mutex_t threads_mutex = PTHREAD_MUTEX_INITIALIZER;
64
65 struct sys_mbox_msg {
66   struct sys_mbox_msg *next;
67   void *msg;
68 };
69
70 #define SYS_MBOX_SIZE 128
71
72 struct sys_mbox {
73   int first, last;
74   void *msgs[SYS_MBOX_SIZE];
75   struct sys_sem *mail;
76   struct sys_sem *mutex;
77   int wait_send;
78 };
79
80 struct sys_sem {
81   unsigned int c;
82   pthread_cond_t cond;
83   pthread_mutex_t mutex;
84 };
85
86 struct sys_thread {
87   struct sys_thread *next;
88   struct sys_timeouts timeouts;
89   pthread_t pthread;
90 };
91
92
93 static struct timeval starttime;
94
95 static pthread_mutex_t lwprot_mutex = PTHREAD_MUTEX_INITIALIZER;
96 static pthread_t lwprot_thread = (pthread_t) 0xDEAD;
97 static int lwprot_count = 0;
98
99 static struct sys_sem *sys_sem_new_(u8_t count);
100 static void sys_sem_free_(struct sys_sem *sem);
101
102 static u32_t cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex,
103                        u32_t timeout);
104
105 /*-----------------------------------------------------------------------------------*/
106 static struct sys_thread * 
107 introduce_thread(pthread_t id)
108 {
109   struct sys_thread *thread;
110   
111   thread = malloc(sizeof(struct sys_thread));
112     
113   if (thread != NULL) {
114     pthread_mutex_lock(&threads_mutex);
115     thread->next = threads;
116     thread->timeouts.next = NULL;
117     thread->pthread = id;
118     threads = thread;
119     pthread_mutex_unlock(&threads_mutex);
120   }
121     
122   return thread;
123 }
124 /*-----------------------------------------------------------------------------------*/
125 static struct sys_thread *
126 current_thread(void)
127 {
128   struct sys_thread *st;
129   pthread_t pt;
130   pt = pthread_self();
131   pthread_mutex_lock(&threads_mutex);
132
133   for(st = threads; st != NULL; st = st->next) {    
134     if (pthread_equal(st->pthread, pt)) {
135       pthread_mutex_unlock(&threads_mutex);
136       
137       return st;
138     }
139   }
140
141   pthread_mutex_unlock(&threads_mutex);
142
143   st = introduce_thread(pt);
144
145   if (!st) {
146     printf("current_thread???\n");
147     abort();
148   }
149
150   return st;
151 }
152 /*-----------------------------------------------------------------------------------*/
153 sys_thread_t
154 sys_thread_new(char *name, void (* function)(void *arg), void *arg, int stacksize, int prio)
155 {
156   int code;
157   pthread_t tmp;
158   struct sys_thread *st = NULL;
159   
160   code = pthread_create(&tmp,
161                         NULL, 
162                         (void *(*)(void *)) 
163                         function, 
164                         arg);
165   
166   if (0 == code) {
167     st = introduce_thread(tmp);
168   }
169   
170   if (NULL == st) {
171     LWIP_DEBUGF(SYS_DEBUG, ("sys_thread_new: pthread_create %d, st = 0x%x",
172                        code, (int)st));
173     abort();
174   }
175   return st;
176 }
177 /*-----------------------------------------------------------------------------------*/
178 struct sys_mbox *
179 sys_mbox_new(int size)
180 {
181   struct sys_mbox *mbox;
182   
183   mbox = malloc(sizeof(struct sys_mbox));
184   if (mbox != NULL) {
185     mbox->first = mbox->last = 0;
186     mbox->mail = sys_sem_new_(0);
187     mbox->mutex = sys_sem_new_(1);
188     mbox->wait_send = 0;
189   
190 #if SYS_STATS
191     lwip_stats.sys.mbox.used++;
192     if (lwip_stats.sys.mbox.used > lwip_stats.sys.mbox.max) {
193       lwip_stats.sys.mbox.max = lwip_stats.sys.mbox.used;
194     }
195 #endif /* SYS_STATS */
196   }
197   return mbox;
198 }
199 /*-----------------------------------------------------------------------------------*/
200 void
201 sys_mbox_free(struct sys_mbox *mbox)
202 {
203   if (mbox != SYS_MBOX_NULL) {
204 #if SYS_STATS
205     lwip_stats.sys.mbox.used--;
206 #endif /* SYS_STATS */
207     sys_sem_wait(mbox->mutex);
208     
209     sys_sem_free_(mbox->mail);
210     sys_sem_free_(mbox->mutex);
211     mbox->mail = mbox->mutex = NULL;
212     /*  LWIP_DEBUGF("sys_mbox_free: mbox 0x%lx\n", mbox); */
213     free(mbox);
214   }
215 }
216 /*-----------------------------------------------------------------------------------*/
217 err_t
218 sys_mbox_trypost(struct sys_mbox *mbox, void *msg)
219 {
220   u8_t first;
221   
222   sys_sem_wait(mbox->mutex);
223   
224   LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_trypost: mbox %p msg %p\n",
225                           (void *)mbox, (void *)msg));
226   
227   if ((mbox->last + 1) >= (mbox->first + SYS_MBOX_SIZE))
228     return ERR_MEM;
229
230   mbox->msgs[mbox->last % SYS_MBOX_SIZE] = msg;
231   
232   if (mbox->last == mbox->first) {
233     first = 1;
234   } else {
235     first = 0;
236   }
237   
238   mbox->last++;
239   
240   if (first) {
241     sys_sem_signal(mbox->mail);
242   }
243
244   sys_sem_signal(mbox->mutex);
245
246   return ERR_OK;
247 }
248 /*-----------------------------------------------------------------------------------*/
249 void
250 sys_mbox_post(struct sys_mbox *mbox, void *msg)
251 {
252   u8_t first;
253   
254   sys_sem_wait(mbox->mutex);
255   
256   LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_post: mbox %p msg %p\n", (void *)mbox, (void *)msg));
257   
258   while ((mbox->last + 1) >= (mbox->first + SYS_MBOX_SIZE)) {
259     mbox->wait_send++;
260     sys_sem_signal(mbox->mutex);
261     sys_arch_sem_wait(mbox->mail, 0);
262     sys_arch_sem_wait(mbox->mutex, 0);
263     mbox->wait_send--;
264   }
265   
266   mbox->msgs[mbox->last % SYS_MBOX_SIZE] = msg;
267   
268   if (mbox->last == mbox->first) {
269     first = 1;
270   } else {
271     first = 0;
272   }
273   
274   mbox->last++;
275   
276   if (first) {
277     sys_sem_signal(mbox->mail);
278   }
279
280   sys_sem_signal(mbox->mutex);
281 }
282 /*-----------------------------------------------------------------------------------*/
283 u32_t
284 sys_arch_mbox_tryfetch(struct sys_mbox *mbox, void **msg)
285 {
286   sys_arch_sem_wait(mbox->mutex, 0);
287
288   if (mbox->first == mbox->last) {
289     sys_sem_signal(mbox->mutex);
290     return SYS_MBOX_EMPTY;
291   }
292
293   if (msg != NULL) {
294     LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_tryfetch: mbox %p msg %p\n", (void *)mbox, *msg));
295     *msg = mbox->msgs[mbox->first % SYS_MBOX_SIZE];
296   }
297   else{
298     LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_tryfetch: mbox %p, null msg\n", (void *)mbox));
299   }
300
301   mbox->first++;
302   
303   if (mbox->wait_send) {
304     sys_sem_signal(mbox->mail);
305   }
306
307   sys_sem_signal(mbox->mutex);
308
309   return 0;
310 }
311 /*-----------------------------------------------------------------------------------*/
312 u32_t
313 sys_arch_mbox_fetch(struct sys_mbox *mbox, void **msg, u32_t timeout)
314 {
315   u32_t time = 0;
316   
317   /* The mutex lock is quick so we don't bother with the timeout
318      stuff here. */
319   sys_arch_sem_wait(mbox->mutex, 0);
320
321   while (mbox->first == mbox->last) {
322     sys_sem_signal(mbox->mutex);
323     
324     /* We block while waiting for a mail to arrive in the mailbox. We
325        must be prepared to timeout. */
326     if (timeout != 0) {
327       time = sys_arch_sem_wait(mbox->mail, timeout);
328       
329       if (time == SYS_ARCH_TIMEOUT) {
330         return SYS_ARCH_TIMEOUT;
331       }
332     } else {
333       sys_arch_sem_wait(mbox->mail, 0);
334     }
335     
336     sys_arch_sem_wait(mbox->mutex, 0);
337   }
338
339   if (msg != NULL) {
340     LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_fetch: mbox %p msg %p\n", (void *)mbox, *msg));
341     *msg = mbox->msgs[mbox->first % SYS_MBOX_SIZE];
342   }
343   else{
344     LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_fetch: mbox %p, null msg\n", (void *)mbox));
345   }
346
347   mbox->first++;
348   
349   if (mbox->wait_send) {
350     sys_sem_signal(mbox->mail);
351   }
352
353   sys_sem_signal(mbox->mutex);
354
355   return time;
356 }
357 /*-----------------------------------------------------------------------------------*/
358 struct sys_sem *
359 sys_sem_new(u8_t count)
360 {
361 #if SYS_STATS
362   lwip_stats.sys.sem.used++;
363   if (lwip_stats.sys.sem.used > lwip_stats.sys.sem.max) {
364     lwip_stats.sys.sem.max = lwip_stats.sys.sem.used;
365   }
366 #endif /* SYS_STATS */
367   return sys_sem_new_(count);
368 }
369
370 /*-----------------------------------------------------------------------------------*/
371 static struct sys_sem *
372 sys_sem_new_(u8_t count)
373 {
374   struct sys_sem *sem;
375   
376   sem = malloc(sizeof(struct sys_sem));
377   if (sem != NULL) {
378     sem->c = count;
379     pthread_cond_init(&(sem->cond), NULL);
380     pthread_mutex_init(&(sem->mutex), NULL);
381   }
382   return sem;
383 }
384
385 /*-----------------------------------------------------------------------------------*/
386 static u32_t
387 cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex, u32_t timeout)
388 {
389   int tdiff;
390   unsigned long sec, usec;
391   struct timeval rtime1, rtime2;
392   struct timespec ts;
393   struct timezone tz;
394   int retval;
395   
396   if (timeout > 0) {
397     /* Get a timestamp and add the timeout value. */
398     gettimeofday(&rtime1, &tz);
399     sec = rtime1.tv_sec;
400     usec = rtime1.tv_usec;
401     usec += timeout % 1000 * 1000;
402     sec += (int)(timeout / 1000) + (int)(usec / 1000000);
403     usec = usec % 1000000;
404     ts.tv_nsec = usec * 1000;
405     ts.tv_sec = sec;
406     
407     retval = pthread_cond_timedwait(cond, mutex, &ts);
408     
409     if (retval == ETIMEDOUT) {
410       return SYS_ARCH_TIMEOUT;
411     } else {
412       /* Calculate for how long we waited for the cond. */
413       gettimeofday(&rtime2, &tz);
414       tdiff = (rtime2.tv_sec - rtime1.tv_sec) * 1000 +
415         (rtime2.tv_usec - rtime1.tv_usec) / 1000;
416       
417       if (tdiff <= 0) {
418         return 0;
419       }
420       
421       return tdiff;
422     }
423   } else {
424     pthread_cond_wait(cond, mutex);
425     return SYS_ARCH_TIMEOUT;
426   }
427 }
428 /*-----------------------------------------------------------------------------------*/
429 u32_t
430 sys_arch_sem_wait(struct sys_sem *sem, u32_t timeout)
431 {
432   u32_t time = 0;
433   
434   pthread_mutex_lock(&(sem->mutex));
435   while (sem->c <= 0) {
436     if (timeout > 0) {
437       time = cond_wait(&(sem->cond), &(sem->mutex), timeout);
438       
439       if (time == SYS_ARCH_TIMEOUT) {
440         pthread_mutex_unlock(&(sem->mutex));
441         return SYS_ARCH_TIMEOUT;
442       }
443       /*      pthread_mutex_unlock(&(sem->mutex));
444               return time; */
445     } else {
446       cond_wait(&(sem->cond), &(sem->mutex), 0);
447     }
448   }
449   sem->c--;
450   pthread_mutex_unlock(&(sem->mutex));
451   return time;
452 }
453 /*-----------------------------------------------------------------------------------*/
454 void
455 sys_sem_signal(struct sys_sem *sem)
456 {
457   pthread_mutex_lock(&(sem->mutex));
458   sem->c++;
459
460   if (sem->c > 1) {
461     sem->c = 1;
462   }
463
464   pthread_cond_broadcast(&(sem->cond));
465   pthread_mutex_unlock(&(sem->mutex));
466 }
467 /*-----------------------------------------------------------------------------------*/
468 void
469 sys_sem_free(struct sys_sem *sem)
470 {
471   if (sem != SYS_SEM_NULL) {
472 #if SYS_STATS
473     lwip_stats.sys.sem.used--;
474 #endif /* SYS_STATS */
475     sys_sem_free_(sem);
476   }
477 }
478
479 /*-----------------------------------------------------------------------------------*/
480 static void
481 sys_sem_free_(struct sys_sem *sem)
482 {
483   pthread_cond_destroy(&(sem->cond));
484   pthread_mutex_destroy(&(sem->mutex));
485   free(sem);
486 }
487 /*-----------------------------------------------------------------------------------*/
488 unsigned long
489 sys_unix_now()
490 {
491   struct timeval tv;
492   struct timezone tz;
493   long sec, usec;
494   unsigned long msec;
495   gettimeofday(&tv, &tz);
496   
497   sec = tv.tv_sec - starttime.tv_sec;
498   usec = tv.tv_usec - starttime.tv_usec;
499   msec = sec * 1000 + usec / 1000;
500     
501   return msec;
502 }
503 /*-----------------------------------------------------------------------------------*/
504 void
505 sys_init()
506 {
507   struct timezone tz;
508   gettimeofday(&starttime, &tz);
509 }
510 /*-----------------------------------------------------------------------------------*/
511 struct sys_timeouts *
512 sys_arch_timeouts(void)
513 {
514   struct sys_thread *thread;
515
516   thread = current_thread();
517   return &thread->timeouts;
518 }
519 /*-----------------------------------------------------------------------------------*/
520 /** sys_prot_t sys_arch_protect(void)
521
522 This optional function does a "fast" critical region protection and returns
523 the previous protection level. This function is only called during very short
524 critical regions. An embedded system which supports ISR-based drivers might
525 want to implement this function by disabling interrupts. Task-based systems
526 might want to implement this by using a mutex or disabling tasking. This
527 function should support recursive calls from the same task or interrupt. In
528 other words, sys_arch_protect() could be called while already protected. In
529 that case the return value indicates that it is already protected.
530
531 sys_arch_protect() is only required if your port is supporting an operating
532 system.
533 */
534 sys_prot_t
535 sys_arch_protect(void)
536 {
537     /* Note that for the UNIX port, we are using a lightweight mutex, and our
538      * own counter (which is locked by the mutex). The return code is not actually
539      * used. */
540     if (lwprot_thread != pthread_self())
541     {
542         /* We are locking the mutex where it has not been locked before *
543         * or is being locked by another thread */
544         pthread_mutex_lock(&lwprot_mutex);
545         lwprot_thread = pthread_self();
546         lwprot_count = 1;
547     }
548     else
549         /* It is already locked by THIS thread */
550         lwprot_count++;
551     return 0;
552 }
553 /*-----------------------------------------------------------------------------------*/
554 /** void sys_arch_unprotect(sys_prot_t pval)
555
556 This optional function does a "fast" set of critical region protection to the
557 value specified by pval. See the documentation for sys_arch_protect() for
558 more information. This function is only required if your port is supporting
559 an operating system.
560 */
561 void
562 sys_arch_unprotect(sys_prot_t pval)
563 {
564     if (lwprot_thread == pthread_self())
565     {
566         if (--lwprot_count == 0)
567         {
568             lwprot_thread = (pthread_t) 0xDEAD;
569             pthread_mutex_unlock(&lwprot_mutex);
570         }
571     }
572 }
573
574 /*-----------------------------------------------------------------------------------*/
575
576 #ifndef MAX_JIFFY_OFFSET
577 #define MAX_JIFFY_OFFSET ((~0UL >> 1)-1)
578 #endif
579
580 #ifndef HZ
581 #define HZ 100
582 #endif
583
584 unsigned long
585 sys_jiffies(void)
586 {
587     struct timeval tv;
588     unsigned long sec = tv.tv_sec;
589     long usec = tv.tv_usec;
590
591     gettimeofday(&tv,NULL);
592
593     if (sec >= (MAX_JIFFY_OFFSET / HZ))
594         return MAX_JIFFY_OFFSET;
595     usec += 1000000L / HZ - 1;
596     usec /= 1000000L / HZ;
597     return HZ * sec + usec;
598 }
599
600 #if PPP_DEBUG
601
602 #include <stdarg.h>
603
604 void ppp_trace(int level, const char *format, ...)
605 {
606     va_list args;
607
608     (void)level;
609     va_start(args, format);
610     vprintf(format, args);
611     va_end(args);
612 }
613 #endif