3 * Copyright (c) 2020 Project CHIP Authors
4 * Copyright (c) 2014-2017 Nest Labs, Inc.
5 * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
22 * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
23 * All rights reserved.
25 * Redistribution and use in source and binary forms, with or without modification,
26 * are permitted provided that the following conditions are met:
28 * 1. Redistributions of source code must retain the above copyright notice,
29 * this list of conditions and the following disclaimer.
30 * 2. Redistributions in binary form must reproduce the above copyright notice,
31 * this list of conditions and the following disclaimer in the documentation
32 * and/or other materials provided with the distribution.
33 * 3. The name of the author may not be used to endorse or promote products
34 * derived from this software without specific prior written permission.
36 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
38 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
39 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
40 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
41 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
42 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
43 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
44 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
47 * This file is part of the lwIP TCP/IP stack.
49 * Author: Adam Dunkels <adam@sics.se>
54 * Wed Apr 17 16:05:29 EDT 2002 (James Roth)
56 * - Fixed an unlikely sys_thread_new() race condition.
58 * - Made current_thread() work with threads which where
59 * not created with sys_thread_new(). This includes
60 * the main thread and threads made with pthread_create().
62 * - Catch overflows where more than SYS_MBOX_SIZE messages
63 * are waiting to be read. The sys_mbox_post() routine
64 * will block until there is more room instead of just
67 #include "lwip/debug.h"
73 #include <sys/types.h>
76 #include <support/CHIPPlatformMemory.h>
79 #include "lwip/stats.h"
82 #define UMAX(a, b) ((a) > (b) ? (a) : (b))
84 static struct timeval starttime;
88 static struct sys_thread * threads = NULL;
89 static pthread_mutex_t threads_mutex = PTHREAD_MUTEX_INITIALIZER;
93 struct sys_mbox_msg * next;
97 #define SYS_MBOX_SIZE 128
102 void * msgs[SYS_MBOX_SIZE];
103 struct sys_sem * not_empty;
104 struct sys_sem * not_full;
105 struct sys_sem * mutex;
113 pthread_mutex_t mutex;
118 struct sys_thread * next;
122 #if SYS_LIGHTWEIGHT_PROT
123 static pthread_mutex_t lwprot_mutex = PTHREAD_MUTEX_INITIALIZER;
124 static pthread_t lwprot_thread = (pthread_t) 0xDEAD;
125 static int lwprot_count = 0;
126 #endif /* SYS_LIGHTWEIGHT_PROT */
128 static struct sys_sem * sys_sem_new_internal(u8_t count);
129 static void sys_sem_free_internal(struct sys_sem * sem);
131 static u32_t cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex, u32_t timeout);
133 /*-----------------------------------------------------------------------------------*/
134 static struct sys_thread * introduce_thread(pthread_t id)
136 struct sys_thread * thread;
138 thread = (struct sys_thread *) CHIPPlatformMemoryAlloc(sizeof(struct sys_thread));
142 pthread_mutex_lock(&threads_mutex);
143 thread->next = threads;
144 thread->pthread = id;
146 pthread_mutex_unlock(&threads_mutex);
151 /*-----------------------------------------------------------------------------------*/
152 static void finish_thread(struct sys_thread * thread)
154 struct sys_thread * cursor;
155 struct sys_thread * previous;
159 pthread_mutex_lock(&threads_mutex);
163 while (cursor != NULL)
165 if (cursor == thread)
167 if (previous != NULL)
169 previous->next = cursor->next;
173 threads = cursor->next;
180 cursor = cursor->next;
183 pthread_mutex_unlock(&threads_mutex);
184 CHIPPlatformMemoryFree(thread);
187 /*-----------------------------------------------------------------------------------*/
188 sys_thread_t sys_thread_new(const char * name, lwip_thread_fn function, void * arg, int stacksize, int prio)
192 struct sys_thread * st = NULL;
193 LWIP_UNUSED_ARG(name);
194 LWIP_UNUSED_ARG(stacksize);
195 LWIP_UNUSED_ARG(prio);
197 code = pthread_create(&tmp, NULL, (void * (*) (void *) ) function, arg);
201 st = introduce_thread(tmp);
206 LWIP_DEBUGF(SYS_DEBUG, ("sys_thread_new: pthread_create %d, st = 0x%lx", code, (unsigned long) st));
211 /*-----------------------------------------------------------------------------------*/
212 err_t sys_thread_finish(sys_thread_t t)
216 code = pthread_join(t->pthread, NULL);
225 /*-----------------------------------------------------------------------------------*/
226 err_t sys_mbox_new_extra(void * pool, struct sys_mbox ** mb, int size)
228 return sys_mbox_new(mb, size);
231 err_t sys_mbox_new(struct sys_mbox ** mb, int size)
233 struct sys_mbox * mbox;
234 LWIP_UNUSED_ARG(size);
236 mbox = (struct sys_mbox *) CHIPPlatformMemoryAlloc(sizeof(struct sys_mbox));
241 mbox->first = mbox->last = 0;
242 mbox->not_empty = sys_sem_new_internal(0);
243 mbox->not_full = sys_sem_new_internal(0);
244 mbox->mutex = sys_sem_new_internal(1);
247 SYS_STATS_INC_USED(mbox);
251 /*-----------------------------------------------------------------------------------*/
252 void sys_mbox_free(struct sys_mbox ** mb)
254 if ((mb != NULL) && (*mb != SYS_MBOX_NULL))
256 struct sys_mbox * mbox = *mb;
257 SYS_STATS_DEC(mbox.used);
258 sys_arch_sem_wait(&mbox->mutex, 0);
260 sys_sem_free_internal(mbox->not_empty);
261 sys_sem_free_internal(mbox->not_full);
262 sys_sem_free_internal(mbox->mutex);
263 mbox->not_empty = mbox->not_full = mbox->mutex = NULL;
264 /* LWIP_DEBUGF("sys_mbox_free: mbox 0x%lx\n", mbox); */
265 CHIPPlatformMemoryFree(mbox);
268 /*-----------------------------------------------------------------------------------*/
269 err_t sys_mbox_trypost(struct sys_mbox ** mb, void * msg)
272 struct sys_mbox * mbox;
273 LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL));
276 sys_arch_sem_wait(&mbox->mutex, 0);
278 LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_trypost: mbox %p msg %p\n", (void *) mbox, (void *) msg));
280 if ((mbox->last + 1) >= (mbox->first + SYS_MBOX_SIZE))
282 sys_sem_signal(&mbox->mutex);
286 mbox->msgs[mbox->last % SYS_MBOX_SIZE] = msg;
288 if (mbox->last == mbox->first)
301 sys_sem_signal(&mbox->not_empty);
304 sys_sem_signal(&mbox->mutex);
308 /*-----------------------------------------------------------------------------------*/
309 void sys_mbox_post(struct sys_mbox ** mb, void * msg)
312 struct sys_mbox * mbox;
313 LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL));
316 sys_arch_sem_wait(&mbox->mutex, 0);
318 LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_post: mbox %p msg %p\n", (void *) mbox, (void *) msg));
320 while ((mbox->last + 1) >= (mbox->first + SYS_MBOX_SIZE))
323 sys_sem_signal(&mbox->mutex);
324 sys_arch_sem_wait(&mbox->not_full, 0);
325 sys_arch_sem_wait(&mbox->mutex, 0);
329 mbox->msgs[mbox->last % SYS_MBOX_SIZE] = msg;
331 if (mbox->last == mbox->first)
344 sys_sem_signal(&mbox->not_empty);
347 sys_sem_signal(&mbox->mutex);
349 /*-----------------------------------------------------------------------------------*/
350 u32_t sys_arch_mbox_tryfetch(struct sys_mbox ** mb, void ** msg)
352 struct sys_mbox * mbox;
353 LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL));
356 sys_arch_sem_wait(&mbox->mutex, 0);
358 if (mbox->first == mbox->last)
360 sys_sem_signal(&mbox->mutex);
361 return SYS_MBOX_EMPTY;
366 LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_tryfetch: mbox %p msg %p\n", (void *) mbox, *msg));
367 *msg = mbox->msgs[mbox->first % SYS_MBOX_SIZE];
371 LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_tryfetch: mbox %p, null msg\n", (void *) mbox));
378 sys_sem_signal(&mbox->not_full);
381 sys_sem_signal(&mbox->mutex);
385 /*-----------------------------------------------------------------------------------*/
386 u32_t sys_arch_mbox_fetch(struct sys_mbox ** mb, void ** msg, u32_t timeout)
388 u32_t time_needed = 0;
389 struct sys_mbox * mbox;
390 LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL));
393 /* The mutex lock is quick so we don't bother with the timeout
395 sys_arch_sem_wait(&mbox->mutex, 0);
397 while (mbox->first == mbox->last)
399 sys_sem_signal(&mbox->mutex);
401 /* We block while waiting for a mail to arrive in the mailbox. We
402 must be prepared to timeout. */
405 time_needed = sys_arch_sem_wait(&mbox->not_empty, timeout);
407 if (time_needed == SYS_ARCH_TIMEOUT)
409 return SYS_ARCH_TIMEOUT;
414 sys_arch_sem_wait(&mbox->not_empty, 0);
417 sys_arch_sem_wait(&mbox->mutex, 0);
422 LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_fetch: mbox %p msg %p\n", (void *) mbox, *msg));
423 *msg = mbox->msgs[mbox->first % SYS_MBOX_SIZE];
427 LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_fetch: mbox %p, null msg\n", (void *) mbox));
434 sys_sem_signal(&mbox->not_full);
437 sys_sem_signal(&mbox->mutex);
441 /*-----------------------------------------------------------------------------------*/
442 static struct sys_sem * sys_sem_new_internal(u8_t count)
444 struct sys_sem * sem;
446 sem = (struct sys_sem *) CHIPPlatformMemoryAlloc(sizeof(struct sys_sem));
450 pthread_cond_init(&(sem->cond), NULL);
451 pthread_mutex_init(&(sem->mutex), NULL);
455 /*-----------------------------------------------------------------------------------*/
456 err_t sys_sem_new(struct sys_sem ** sem, u8_t count)
458 SYS_STATS_INC_USED(sem);
459 *sem = sys_sem_new_internal(count);
466 /*-----------------------------------------------------------------------------------*/
467 static u32_t cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex, u32_t timeout)
471 struct timeval rtime1, rtime2;
477 /* Get a timestamp and add the timeout value. */
478 gettimeofday(&rtime1, NULL);
480 usec = rtime1.tv_usec;
481 usec += timeout % 1000 * 1000;
482 sec += (int) (timeout / 1000) + (int) (usec / 1000000);
483 usec = usec % 1000000;
484 ts.tv_nsec = usec * 1000;
487 retval = pthread_cond_timedwait(cond, mutex, &ts);
489 if (retval == ETIMEDOUT)
491 return SYS_ARCH_TIMEOUT;
494 /* Calculate for how long we waited for the cond. */
495 gettimeofday(&rtime2, NULL);
496 tdiff = (rtime2.tv_sec - rtime1.tv_sec) * 1000 + (rtime2.tv_usec - rtime1.tv_usec) / 1000;
503 return (u32_t) tdiff;
506 pthread_cond_wait(cond, mutex);
510 /*-----------------------------------------------------------------------------------*/
511 u32_t sys_arch_sem_wait(struct sys_sem ** s, u32_t timeout)
513 u32_t time_needed = 0;
514 struct sys_sem * sem;
515 LWIP_ASSERT("invalid sem", (s != NULL) && (*s != NULL));
518 pthread_mutex_lock(&(sem->mutex));
523 time_needed = cond_wait(&(sem->cond), &(sem->mutex), timeout);
525 if (time_needed == SYS_ARCH_TIMEOUT)
527 pthread_mutex_unlock(&(sem->mutex));
528 return SYS_ARCH_TIMEOUT;
530 /* pthread_mutex_unlock(&(sem->mutex));
531 return time_needed; */
535 cond_wait(&(sem->cond), &(sem->mutex), 0);
539 pthread_mutex_unlock(&(sem->mutex));
542 /*-----------------------------------------------------------------------------------*/
543 void sys_sem_signal(struct sys_sem ** s)
545 struct sys_sem * sem;
546 LWIP_ASSERT("invalid sem", (s != NULL) && (*s != NULL));
549 pthread_mutex_lock(&(sem->mutex));
557 pthread_cond_broadcast(&(sem->cond));
558 pthread_mutex_unlock(&(sem->mutex));
560 /*-----------------------------------------------------------------------------------*/
561 static void sys_sem_free_internal(struct sys_sem * sem)
563 pthread_cond_destroy(&(sem->cond));
564 pthread_mutex_destroy(&(sem->mutex));
565 CHIPPlatformMemoryFree(sem);
567 /*-----------------------------------------------------------------------------------*/
568 void sys_sem_free(struct sys_sem ** sem)
570 if ((sem != NULL) && (*sem != SYS_SEM_NULL))
572 SYS_STATS_DEC(sem.used);
573 sys_sem_free_internal(*sem);
577 /*-----------------------------------------------------------------------------------*/
582 gettimeofday(&tv, NULL);
584 msec = (u32_t)((tv.tv_sec - starttime.tv_sec) * 1000 + (tv.tv_usec - starttime.tv_usec) / 1000);
588 /*-----------------------------------------------------------------------------------*/
591 gettimeofday(&starttime, NULL);
593 /*-----------------------------------------------------------------------------------*/
594 #if SYS_LIGHTWEIGHT_PROT
595 /** sys_prot_t sys_arch_protect(void)
597 This optional function does a "fast" critical region protection and returns
598 the previous protection level. This function is only called during very short
599 critical regions. An embedded system which supports ISR-based drivers might
600 want to implement this function by disabling interrupts. Task-based systems
601 might want to implement this by using a mutex or disabling tasking. This
602 function should support recursive calls from the same task or interrupt. In
603 other words, sys_arch_protect() could be called while already protected. In
604 that case the return value indicates that it is already protected.
606 sys_arch_protect() is only required if your port is supporting an operating
609 sys_prot_t sys_arch_protect(void)
611 /* Note that for the UNIX port, we are using a lightweight mutex, and our
612 * own counter (which is locked by the mutex). The return code is not actually
614 if (lwprot_thread != pthread_self())
616 /* We are locking the mutex where it has not been locked before *
617 * or is being locked by another thread */
618 pthread_mutex_lock(&lwprot_mutex);
619 lwprot_thread = pthread_self();
623 /* It is already locked by THIS thread */
627 /*-----------------------------------------------------------------------------------*/
629 /** void sys_arch_unprotect(sys_prot_t pval)
631 This optional function does a "fast" set of critical region protection to the
632 value specified by pval. See the documentation for sys_arch_protect() for
633 more information. This function is only required if your port is supporting
636 void sys_arch_unprotect(sys_prot_t pval)
638 LWIP_UNUSED_ARG(pval);
639 if (lwprot_thread == pthread_self())
641 if (--lwprot_count == 0)
643 lwprot_thread = (pthread_t) 0xDEAD;
644 pthread_mutex_unlock(&lwprot_mutex);
648 #endif /* SYS_LIGHTWEIGHT_PROT */
650 /*-----------------------------------------------------------------------------------*/
652 #ifndef MAX_JIFFY_OFFSET
653 #define MAX_JIFFY_OFFSET ((~0U >> 1) - 1)
660 u32_t sys_jiffies(void)
666 gettimeofday(&tv, NULL);
667 sec = tv.tv_sec - starttime.tv_sec;
670 if (sec >= (MAX_JIFFY_OFFSET / HZ))
671 return MAX_JIFFY_OFFSET;
672 usec += 1000000L / HZ - 1;
673 usec /= 1000000L / HZ;
674 return HZ * sec + usec;
681 void ppp_trace(int level, const char * format, ...)
686 va_start(args, format);
687 vprintf(format, args);
694 unsigned char gLwIP_DebugFlags = 0;