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 timeval starttime;
63
64 #if !NO_SYS
65
66 static struct sys_thread *threads = NULL;
67 static pthread_mutex_t threads_mutex = PTHREAD_MUTEX_INITIALIZER;
68
69 struct sys_mbox_msg {
70 struct sys_mbox_msg *next;
71 void *msg;
72 };
73
74 #define SYS_MBOX_SIZE 128
75
76 struct sys_mbox {
77 int first, last;
78 void *msgs[SYS_MBOX_SIZE];
79 struct sys_sem *not_empty;
80 struct sys_sem *not_full;
81 struct sys_sem *mutex;
82 int wait_send;
83 };
84
85 struct sys_sem {
86 unsigned int c;
87 pthread_cond_t cond;
88 pthread_mutex_t mutex;
89 };
90
91 struct sys_thread {
92 struct sys_thread *next;
93 pthread_t pthread;
94 };
95
96 #if SYS_LIGHTWEIGHT_PROT
97 static pthread_mutex_t lwprot_mutex = PTHREAD_MUTEX_INITIALIZER;
98 static pthread_t lwprot_thread = (pthread_t)0xDEAD;
99 static int lwprot_count = 0;
100 #endif /* SYS_LIGHTWEIGHT_PROT */
101
102 static struct sys_sem *sys_sem_new_internal(u8_t count);
103 static void sys_sem_free_internal(struct sys_sem *sem);
104
105 static u32_t cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex,
106 u32_t timeout);
107
108 /*-----------------------------------------------------------------------------------*/
109 static struct sys_thread *
introduce_thread(pthread_t id)110 introduce_thread(pthread_t id)
111 {
112 struct sys_thread *thread;
113
114 thread = (struct sys_thread *)malloc(sizeof(struct sys_thread));
115
116 if (thread != NULL) {
117 pthread_mutex_lock(&threads_mutex);
118 thread->next = threads;
119 thread->pthread = id;
120 threads = thread;
121 pthread_mutex_unlock(&threads_mutex);
122 }
123
124 return thread;
125 }
126 /*-----------------------------------------------------------------------------------*/
127 sys_thread_t
sys_thread_new(const char * name,lwip_thread_fn function,void * arg,int stacksize,int prio)128 sys_thread_new(const char *name, lwip_thread_fn function, void *arg, int stacksize, int prio)
129 {
130 int code;
131 pthread_t tmp;
132 struct sys_thread *st = NULL;
133 LWIP_UNUSED_ARG(name);
134 LWIP_UNUSED_ARG(stacksize);
135 LWIP_UNUSED_ARG(prio);
136
137 code = pthread_create(&tmp,
138 NULL,
139 (void *(*)(void *))
140 function,
141 arg);
142
143 if (0 == code) {
144 st = introduce_thread(tmp);
145 }
146
147 if (NULL == st) {
148 LWIP_DEBUGF(SYS_DEBUG, ("sys_thread_new: pthread_create %d, st = 0x%lx",
149 code, (unsigned long)st));
150 abort();
151 }
152 return st;
153 }
154 /*-----------------------------------------------------------------------------------*/
155 err_t
sys_mbox_new(struct sys_mbox ** mb,int size)156 sys_mbox_new(struct sys_mbox **mb, int size)
157 {
158 struct sys_mbox *mbox;
159 LWIP_UNUSED_ARG(size);
160
161 mbox = (struct sys_mbox *)malloc(sizeof(struct sys_mbox));
162 if (mbox == NULL) {
163 return ERR_MEM;
164 }
165 mbox->first = mbox->last = 0;
166 mbox->not_empty = sys_sem_new_internal(0);
167 mbox->not_full = sys_sem_new_internal(0);
168 mbox->mutex = sys_sem_new_internal(1);
169 mbox->wait_send = 0;
170
171 SYS_STATS_INC_USED(mbox);
172 *mb = mbox;
173 return ERR_OK;
174 }
175 /*-----------------------------------------------------------------------------------*/
176 void
sys_mbox_free(struct sys_mbox ** mb)177 sys_mbox_free(struct sys_mbox **mb)
178 {
179 if ((mb != NULL) && (*mb != SYS_MBOX_NULL)) {
180 struct sys_mbox *mbox = *mb;
181 SYS_STATS_DEC(mbox.used);
182 sys_arch_sem_wait(&mbox->mutex, 0);
183
184 sys_sem_free_internal(mbox->not_empty);
185 sys_sem_free_internal(mbox->not_full);
186 sys_sem_free_internal(mbox->mutex);
187 mbox->not_empty = mbox->not_full = mbox->mutex = NULL;
188 /* LWIP_DEBUGF("sys_mbox_free: mbox 0x%lx\n", mbox); */
189 free(mbox);
190 }
191 }
192 /*-----------------------------------------------------------------------------------*/
193 err_t
sys_mbox_trypost(struct sys_mbox ** mb,void * msg)194 sys_mbox_trypost(struct sys_mbox **mb, void *msg)
195 {
196 u8_t first;
197 struct sys_mbox *mbox;
198 LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL));
199 mbox = *mb;
200
201 sys_arch_sem_wait(&mbox->mutex, 0);
202
203 LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_trypost: mbox %p msg %p\n",
204 (void *)mbox, (void *)msg));
205
206 if ((mbox->last + 1) >= (mbox->first + SYS_MBOX_SIZE)) {
207 sys_sem_signal(&mbox->mutex);
208 return ERR_MEM;
209 }
210
211 mbox->msgs[mbox->last % SYS_MBOX_SIZE] = msg;
212
213 if (mbox->last == mbox->first) {
214 first = 1;
215 } else {
216 first = 0;
217 }
218
219 mbox->last++;
220
221 if (first) {
222 sys_sem_signal(&mbox->not_empty);
223 }
224
225 sys_sem_signal(&mbox->mutex);
226
227 return ERR_OK;
228 }
229 /*-----------------------------------------------------------------------------------*/
230 void
sys_mbox_post(struct sys_mbox ** mb,void * msg)231 sys_mbox_post(struct sys_mbox **mb, void *msg)
232 {
233 u8_t first;
234 struct sys_mbox *mbox;
235 LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL));
236 mbox = *mb;
237
238 sys_arch_sem_wait(&mbox->mutex, 0);
239
240 LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_post: mbox %p msg %p\n", (void *)mbox, (void *)msg));
241
242 while ((mbox->last + 1) >= (mbox->first + SYS_MBOX_SIZE)) {
243 mbox->wait_send++;
244 sys_sem_signal(&mbox->mutex);
245 sys_arch_sem_wait(&mbox->not_full, 0);
246 sys_arch_sem_wait(&mbox->mutex, 0);
247 mbox->wait_send--;
248 }
249
250 mbox->msgs[mbox->last % SYS_MBOX_SIZE] = msg;
251
252 if (mbox->last == mbox->first) {
253 first = 1;
254 } else {
255 first = 0;
256 }
257
258 mbox->last++;
259
260 if (first) {
261 sys_sem_signal(&mbox->not_empty);
262 }
263
264 sys_sem_signal(&mbox->mutex);
265 }
266 /*-----------------------------------------------------------------------------------*/
267 u32_t
sys_arch_mbox_tryfetch(struct sys_mbox ** mb,void ** msg)268 sys_arch_mbox_tryfetch(struct sys_mbox **mb, void **msg)
269 {
270 struct sys_mbox *mbox;
271 LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL));
272 mbox = *mb;
273
274 sys_arch_sem_wait(&mbox->mutex, 0);
275
276 if (mbox->first == mbox->last) {
277 sys_sem_signal(&mbox->mutex);
278 return SYS_MBOX_EMPTY;
279 }
280
281 if (msg != NULL) {
282 LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_tryfetch: mbox %p msg %p\n", (void *)mbox, *msg));
283 *msg = mbox->msgs[mbox->first % SYS_MBOX_SIZE];
284 }
285 else{
286 LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_tryfetch: mbox %p, null msg\n", (void *)mbox));
287 }
288
289 mbox->first++;
290
291 if (mbox->wait_send) {
292 sys_sem_signal(&mbox->not_full);
293 }
294
295 sys_sem_signal(&mbox->mutex);
296
297 return 0;
298 }
299 /*-----------------------------------------------------------------------------------*/
300 u32_t
sys_arch_mbox_fetch(struct sys_mbox ** mb,void ** msg,u32_t timeout)301 sys_arch_mbox_fetch(struct sys_mbox **mb, void **msg, u32_t timeout)
302 {
303 u32_t time_needed = 0;
304 struct sys_mbox *mbox;
305 LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL));
306 mbox = *mb;
307
308 /* The mutex lock is quick so we don't bother with the timeout
309 stuff here. */
310 sys_arch_sem_wait(&mbox->mutex, 0);
311
312 while (mbox->first == mbox->last) {
313 sys_sem_signal(&mbox->mutex);
314
315 /* We block while waiting for a mail to arrive in the mailbox. We
316 must be prepared to timeout. */
317 if (timeout != 0) {
318 time_needed = sys_arch_sem_wait(&mbox->not_empty, timeout);
319
320 if (time_needed == SYS_ARCH_TIMEOUT) {
321 return SYS_ARCH_TIMEOUT;
322 }
323 } else {
324 sys_arch_sem_wait(&mbox->not_empty, 0);
325 }
326
327 sys_arch_sem_wait(&mbox->mutex, 0);
328 }
329
330 if (msg != NULL) {
331 LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_fetch: mbox %p msg %p\n", (void *)mbox, *msg));
332 *msg = mbox->msgs[mbox->first % SYS_MBOX_SIZE];
333 }
334 else{
335 LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_fetch: mbox %p, null msg\n", (void *)mbox));
336 }
337
338 mbox->first++;
339
340 if (mbox->wait_send) {
341 sys_sem_signal(&mbox->not_full);
342 }
343
344 sys_sem_signal(&mbox->mutex);
345
346 return time_needed;
347 }
348 /*-----------------------------------------------------------------------------------*/
349 static struct sys_sem *
sys_sem_new_internal(u8_t count)350 sys_sem_new_internal(u8_t count)
351 {
352 struct sys_sem *sem;
353
354 sem = (struct sys_sem *)malloc(sizeof(struct sys_sem));
355 if (sem != NULL) {
356 sem->c = count;
357 pthread_cond_init(&(sem->cond), NULL);
358 pthread_mutex_init(&(sem->mutex), NULL);
359 }
360 return sem;
361 }
362 /*-----------------------------------------------------------------------------------*/
363 err_t
sys_sem_new(struct sys_sem ** sem,u8_t count)364 sys_sem_new(struct sys_sem **sem, u8_t count)
365 {
366 SYS_STATS_INC_USED(sem);
367 *sem = sys_sem_new_internal(count);
368 if (*sem == NULL) {
369 return ERR_MEM;
370 }
371 return ERR_OK;
372 }
373 /*-----------------------------------------------------------------------------------*/
374 static u32_t
cond_wait(pthread_cond_t * cond,pthread_mutex_t * mutex,u32_t timeout)375 cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex, u32_t timeout)
376 {
377 time_t tdiff;
378 time_t sec, usec;
379 struct timeval rtime1, rtime2;
380 struct timespec ts;
381 int retval;
382
383 if (timeout > 0) {
384 /* Get a timestamp and add the timeout value. */
385 gettimeofday(&rtime1, NULL);
386 sec = rtime1.tv_sec;
387 usec = rtime1.tv_usec;
388 usec += timeout % 1000 * 1000;
389 sec += (int)(timeout / 1000) + (int)(usec / 1000000);
390 usec = usec % 1000000;
391 ts.tv_nsec = usec * 1000;
392 ts.tv_sec = sec;
393
394 retval = pthread_cond_timedwait(cond, mutex, &ts);
395
396 if (retval == ETIMEDOUT) {
397 return SYS_ARCH_TIMEOUT;
398 } else {
399 /* Calculate for how long we waited for the cond. */
400 gettimeofday(&rtime2, NULL);
401 tdiff = (rtime2.tv_sec - rtime1.tv_sec) * 1000 +
402 (rtime2.tv_usec - rtime1.tv_usec) / 1000;
403
404 if (tdiff <= 0) {
405 return 0;
406 }
407 return (u32_t)tdiff;
408 }
409 } else {
410 pthread_cond_wait(cond, mutex);
411 return 0;
412 }
413 }
414 /*-----------------------------------------------------------------------------------*/
415 u32_t
sys_arch_sem_wait(struct sys_sem ** s,u32_t timeout)416 sys_arch_sem_wait(struct sys_sem **s, u32_t timeout)
417 {
418 u32_t time_needed = 0;
419 struct sys_sem *sem;
420 LWIP_ASSERT("invalid sem", (s != NULL) && (*s != NULL));
421 sem = *s;
422
423 pthread_mutex_lock(&(sem->mutex));
424 while (sem->c <= 0) {
425 if (timeout > 0) {
426 time_needed = cond_wait(&(sem->cond), &(sem->mutex), timeout);
427
428 if (time_needed == SYS_ARCH_TIMEOUT) {
429 pthread_mutex_unlock(&(sem->mutex));
430 return SYS_ARCH_TIMEOUT;
431 }
432 /* pthread_mutex_unlock(&(sem->mutex));
433 return time_needed; */
434 } else {
435 cond_wait(&(sem->cond), &(sem->mutex), 0);
436 }
437 }
438 sem->c--;
439 pthread_mutex_unlock(&(sem->mutex));
440 return (u32_t)time_needed;
441 }
442 /*-----------------------------------------------------------------------------------*/
443 void
sys_sem_signal(struct sys_sem ** s)444 sys_sem_signal(struct sys_sem **s)
445 {
446 struct sys_sem *sem;
447 LWIP_ASSERT("invalid sem", (s != NULL) && (*s != NULL));
448 sem = *s;
449
450 pthread_mutex_lock(&(sem->mutex));
451 sem->c++;
452
453 if (sem->c > 1) {
454 sem->c = 1;
455 }
456
457 pthread_cond_broadcast(&(sem->cond));
458 pthread_mutex_unlock(&(sem->mutex));
459 }
460 /*-----------------------------------------------------------------------------------*/
461 static void
sys_sem_free_internal(struct sys_sem * sem)462 sys_sem_free_internal(struct sys_sem *sem)
463 {
464 pthread_cond_destroy(&(sem->cond));
465 pthread_mutex_destroy(&(sem->mutex));
466 free(sem);
467 }
468 /*-----------------------------------------------------------------------------------*/
469 void
sys_sem_free(struct sys_sem ** sem)470 sys_sem_free(struct sys_sem **sem)
471 {
472 if ((sem != NULL) && (*sem != SYS_SEM_NULL)) {
473 SYS_STATS_DEC(sem.used);
474 sys_sem_free_internal(*sem);
475 }
476 }
477 #endif /* !NO_SYS */
478 /*-----------------------------------------------------------------------------------*/
479 u32_t
sys_now(void)480 sys_now(void)
481 {
482 struct timeval tv;
483 u32_t sec, usec, msec;
484 gettimeofday(&tv, NULL);
485
486 sec = (u32_t)(tv.tv_sec - starttime.tv_sec);
487 usec = (u32_t)(tv.tv_usec - starttime.tv_usec);
488 msec = sec * 1000 + usec / 1000;
489
490 return msec;
491 }
492 /*-----------------------------------------------------------------------------------*/
493 void
sys_init(void)494 sys_init(void)
495 {
496 gettimeofday(&starttime, NULL);
497 }
498 /*-----------------------------------------------------------------------------------*/
499 #if SYS_LIGHTWEIGHT_PROT
500 /** sys_prot_t sys_arch_protect(void)
501
502 This optional function does a "fast" critical region protection and returns
503 the previous protection level. This function is only called during very short
504 critical regions. An embedded system which supports ISR-based drivers might
505 want to implement this function by disabling interrupts. Task-based systems
506 might want to implement this by using a mutex or disabling tasking. This
507 function should support recursive calls from the same task or interrupt. In
508 other words, sys_arch_protect() could be called while already protected. In
509 that case the return value indicates that it is already protected.
510
511 sys_arch_protect() is only required if your port is supporting an operating
512 system.
513 */
514 sys_prot_t
sys_arch_protect(void)515 sys_arch_protect(void)
516 {
517 /* Note that for the UNIX port, we are using a lightweight mutex, and our
518 * own counter (which is locked by the mutex). The return code is not actually
519 * used. */
520 if (lwprot_thread != pthread_self())
521 {
522 /* We are locking the mutex where it has not been locked before *
523 * or is being locked by another thread */
524 pthread_mutex_lock(&lwprot_mutex);
525 lwprot_thread = pthread_self();
526 lwprot_count = 1;
527 }
528 else
529 /* It is already locked by THIS thread */
530 lwprot_count++;
531 return 0;
532 }
533 /*-----------------------------------------------------------------------------------*/
534 /** void sys_arch_unprotect(sys_prot_t pval)
535
536 This optional function does a "fast" set of critical region protection to the
537 value specified by pval. See the documentation for sys_arch_protect() for
538 more information. This function is only required if your port is supporting
539 an operating system.
540 */
541 void
sys_arch_unprotect(sys_prot_t pval)542 sys_arch_unprotect(sys_prot_t pval)
543 {
544 LWIP_UNUSED_ARG(pval);
545 if (lwprot_thread == pthread_self())
546 {
547 if (--lwprot_count == 0)
548 {
549 lwprot_thread = (pthread_t) 0xDEAD;
550 pthread_mutex_unlock(&lwprot_mutex);
551 }
552 }
553 }
554 #endif /* SYS_LIGHTWEIGHT_PROT */
555
556 /*-----------------------------------------------------------------------------------*/
557
558 #ifndef MAX_JIFFY_OFFSET
559 #define MAX_JIFFY_OFFSET ((~0U >> 1)-1)
560 #endif
561
562 #ifndef HZ
563 #define HZ 100
564 #endif
565
566 u32_t
sys_jiffies(void)567 sys_jiffies(void)
568 {
569 struct timeval tv;
570 unsigned long sec;
571 long usec;
572
573 gettimeofday(&tv,NULL);
574 sec = tv.tv_sec - starttime.tv_sec;
575 usec = tv.tv_usec;
576
577 if (sec >= (MAX_JIFFY_OFFSET / HZ))
578 return MAX_JIFFY_OFFSET;
579 usec += 1000000L / HZ - 1;
580 usec /= 1000000L / HZ;
581 return HZ * sec + usec;
582 }
583
584 #if PPP_DEBUG
585
586 #include <stdarg.h>
587
ppp_trace(int level,const char * format,...)588 void ppp_trace(int level, const char *format, ...)
589 {
590 va_list args;
591
592 (void)level;
593 va_start(args, format);
594 vprintf(format, args);
595 va_end(args);
596 }
597 #endif
598