Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / lwip / standalone / sys_arch.c
1 /*
2  *
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.
6  *    All rights reserved.
7  *
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
11  *
12  *        http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  */
20
21 /*
22  * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
23  * All rights reserved.
24  *
25  * Redistribution and use in source and binary forms, with or without modification,
26  * are permitted provided that the following conditions are met:
27  *
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.
35  *
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
45  * OF SUCH DAMAGE.
46  *
47  * This file is part of the lwIP TCP/IP stack.
48  *
49  * Author: Adam Dunkels <adam@sics.se>
50  *
51  */
52
53 /*
54  * Wed Apr 17 16:05:29 EDT 2002 (James Roth)
55  *
56  *  - Fixed an unlikely sys_thread_new() race condition.
57  *
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().
61  *
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
65  *    leaking messages.
66  */
67 #include "lwip/debug.h"
68
69 #include <pthread.h>
70 #include <stdlib.h>
71 #include <string.h>
72 #include <sys/time.h>
73 #include <sys/types.h>
74 #include <unistd.h>
75
76 #include <support/CHIPPlatformMemory.h>
77
78 #include "lwip/opt.h"
79 #include "lwip/stats.h"
80 #include "lwip/sys.h"
81
82 #define UMAX(a, b) ((a) > (b) ? (a) : (b))
83
84 static struct timeval starttime;
85
86 #if !NO_SYS
87
88 static struct sys_thread * threads   = NULL;
89 static pthread_mutex_t threads_mutex = PTHREAD_MUTEX_INITIALIZER;
90
91 struct sys_mbox_msg
92 {
93     struct sys_mbox_msg * next;
94     void * msg;
95 };
96
97 #define SYS_MBOX_SIZE 128
98
99 struct sys_mbox
100 {
101     int first, last;
102     void * msgs[SYS_MBOX_SIZE];
103     struct sys_sem * not_empty;
104     struct sys_sem * not_full;
105     struct sys_sem * mutex;
106     int wait_send;
107 };
108
109 struct sys_sem
110 {
111     unsigned int c;
112     pthread_cond_t cond;
113     pthread_mutex_t mutex;
114 };
115
116 struct sys_thread
117 {
118     struct sys_thread * next;
119     pthread_t pthread;
120 };
121
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 */
127
128 static struct sys_sem * sys_sem_new_internal(u8_t count);
129 static void sys_sem_free_internal(struct sys_sem * sem);
130
131 static u32_t cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex, u32_t timeout);
132
133 /*-----------------------------------------------------------------------------------*/
134 static struct sys_thread * introduce_thread(pthread_t id)
135 {
136     struct sys_thread * thread;
137
138     thread = (struct sys_thread *) CHIPPlatformMemoryAlloc(sizeof(struct sys_thread));
139
140     if (thread != NULL)
141     {
142         pthread_mutex_lock(&threads_mutex);
143         thread->next    = threads;
144         thread->pthread = id;
145         threads         = thread;
146         pthread_mutex_unlock(&threads_mutex);
147     }
148
149     return thread;
150 }
151 /*-----------------------------------------------------------------------------------*/
152 static void finish_thread(struct sys_thread * thread)
153 {
154     struct sys_thread * cursor;
155     struct sys_thread * previous;
156
157     if (thread != NULL)
158     {
159         pthread_mutex_lock(&threads_mutex);
160
161         previous = NULL;
162         cursor   = threads;
163         while (cursor != NULL)
164         {
165             if (cursor == thread)
166             {
167                 if (previous != NULL)
168                 {
169                     previous->next = cursor->next;
170                 }
171                 else
172                 {
173                     threads = cursor->next;
174                 }
175                 cursor->next    = NULL;
176                 cursor->pthread = 0;
177                 break;
178             }
179             previous = cursor;
180             cursor   = cursor->next;
181         }
182
183         pthread_mutex_unlock(&threads_mutex);
184         CHIPPlatformMemoryFree(thread);
185     }
186 }
187 /*-----------------------------------------------------------------------------------*/
188 sys_thread_t sys_thread_new(const char * name, lwip_thread_fn function, void * arg, int stacksize, int prio)
189 {
190     int code;
191     pthread_t tmp;
192     struct sys_thread * st = NULL;
193     LWIP_UNUSED_ARG(name);
194     LWIP_UNUSED_ARG(stacksize);
195     LWIP_UNUSED_ARG(prio);
196
197     code = pthread_create(&tmp, NULL, (void * (*) (void *) ) function, arg);
198
199     if (0 == code)
200     {
201         st = introduce_thread(tmp);
202     }
203
204     if (NULL == st)
205     {
206         LWIP_DEBUGF(SYS_DEBUG, ("sys_thread_new: pthread_create %d, st = 0x%lx", code, (unsigned long) st));
207         abort();
208     }
209     return st;
210 }
211 /*-----------------------------------------------------------------------------------*/
212 err_t sys_thread_finish(sys_thread_t t)
213 {
214     int code;
215
216     code = pthread_join(t->pthread, NULL);
217     if (0 == code)
218     {
219         finish_thread(t);
220         return ERR_OK;
221     }
222
223     return ERR_VAL;
224 }
225 /*-----------------------------------------------------------------------------------*/
226 err_t sys_mbox_new_extra(void * pool, struct sys_mbox ** mb, int size)
227 {
228     return sys_mbox_new(mb, size);
229 }
230
231 err_t sys_mbox_new(struct sys_mbox ** mb, int size)
232 {
233     struct sys_mbox * mbox;
234     LWIP_UNUSED_ARG(size);
235
236     mbox = (struct sys_mbox *) CHIPPlatformMemoryAlloc(sizeof(struct sys_mbox));
237     if (mbox == NULL)
238     {
239         return ERR_MEM;
240     }
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);
245     mbox->wait_send          = 0;
246
247     SYS_STATS_INC_USED(mbox);
248     *mb = mbox;
249     return ERR_OK;
250 }
251 /*-----------------------------------------------------------------------------------*/
252 void sys_mbox_free(struct sys_mbox ** mb)
253 {
254     if ((mb != NULL) && (*mb != SYS_MBOX_NULL))
255     {
256         struct sys_mbox * mbox = *mb;
257         SYS_STATS_DEC(mbox.used);
258         sys_arch_sem_wait(&mbox->mutex, 0);
259
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);
266     }
267 }
268 /*-----------------------------------------------------------------------------------*/
269 err_t sys_mbox_trypost(struct sys_mbox ** mb, void * msg)
270 {
271     u8_t first;
272     struct sys_mbox * mbox;
273     LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL));
274     mbox = *mb;
275
276     sys_arch_sem_wait(&mbox->mutex, 0);
277
278     LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_trypost: mbox %p msg %p\n", (void *) mbox, (void *) msg));
279
280     if ((mbox->last + 1) >= (mbox->first + SYS_MBOX_SIZE))
281     {
282         sys_sem_signal(&mbox->mutex);
283         return ERR_MEM;
284     }
285
286     mbox->msgs[mbox->last % SYS_MBOX_SIZE] = msg;
287
288     if (mbox->last == mbox->first)
289     {
290         first = 1;
291     }
292     else
293     {
294         first = 0;
295     }
296
297     mbox->last++;
298
299     if (first)
300     {
301         sys_sem_signal(&mbox->not_empty);
302     }
303
304     sys_sem_signal(&mbox->mutex);
305
306     return ERR_OK;
307 }
308 /*-----------------------------------------------------------------------------------*/
309 void sys_mbox_post(struct sys_mbox ** mb, void * msg)
310 {
311     u8_t first;
312     struct sys_mbox * mbox;
313     LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL));
314     mbox = *mb;
315
316     sys_arch_sem_wait(&mbox->mutex, 0);
317
318     LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_post: mbox %p msg %p\n", (void *) mbox, (void *) msg));
319
320     while ((mbox->last + 1) >= (mbox->first + SYS_MBOX_SIZE))
321     {
322         mbox->wait_send++;
323         sys_sem_signal(&mbox->mutex);
324         sys_arch_sem_wait(&mbox->not_full, 0);
325         sys_arch_sem_wait(&mbox->mutex, 0);
326         mbox->wait_send--;
327     }
328
329     mbox->msgs[mbox->last % SYS_MBOX_SIZE] = msg;
330
331     if (mbox->last == mbox->first)
332     {
333         first = 1;
334     }
335     else
336     {
337         first = 0;
338     }
339
340     mbox->last++;
341
342     if (first)
343     {
344         sys_sem_signal(&mbox->not_empty);
345     }
346
347     sys_sem_signal(&mbox->mutex);
348 }
349 /*-----------------------------------------------------------------------------------*/
350 u32_t sys_arch_mbox_tryfetch(struct sys_mbox ** mb, void ** msg)
351 {
352     struct sys_mbox * mbox;
353     LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL));
354     mbox = *mb;
355
356     sys_arch_sem_wait(&mbox->mutex, 0);
357
358     if (mbox->first == mbox->last)
359     {
360         sys_sem_signal(&mbox->mutex);
361         return SYS_MBOX_EMPTY;
362     }
363
364     if (msg != NULL)
365     {
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];
368     }
369     else
370     {
371         LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_tryfetch: mbox %p, null msg\n", (void *) mbox));
372     }
373
374     mbox->first++;
375
376     if (mbox->wait_send)
377     {
378         sys_sem_signal(&mbox->not_full);
379     }
380
381     sys_sem_signal(&mbox->mutex);
382
383     return 0;
384 }
385 /*-----------------------------------------------------------------------------------*/
386 u32_t sys_arch_mbox_fetch(struct sys_mbox ** mb, void ** msg, u32_t timeout)
387 {
388     u32_t time_needed = 0;
389     struct sys_mbox * mbox;
390     LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL));
391     mbox = *mb;
392
393     /* The mutex lock is quick so we don't bother with the timeout
394        stuff here. */
395     sys_arch_sem_wait(&mbox->mutex, 0);
396
397     while (mbox->first == mbox->last)
398     {
399         sys_sem_signal(&mbox->mutex);
400
401         /* We block while waiting for a mail to arrive in the mailbox. We
402            must be prepared to timeout. */
403         if (timeout != 0)
404         {
405             time_needed = sys_arch_sem_wait(&mbox->not_empty, timeout);
406
407             if (time_needed == SYS_ARCH_TIMEOUT)
408             {
409                 return SYS_ARCH_TIMEOUT;
410             }
411         }
412         else
413         {
414             sys_arch_sem_wait(&mbox->not_empty, 0);
415         }
416
417         sys_arch_sem_wait(&mbox->mutex, 0);
418     }
419
420     if (msg != NULL)
421     {
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];
424     }
425     else
426     {
427         LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_fetch: mbox %p, null msg\n", (void *) mbox));
428     }
429
430     mbox->first++;
431
432     if (mbox->wait_send)
433     {
434         sys_sem_signal(&mbox->not_full);
435     }
436
437     sys_sem_signal(&mbox->mutex);
438
439     return time_needed;
440 }
441 /*-----------------------------------------------------------------------------------*/
442 static struct sys_sem * sys_sem_new_internal(u8_t count)
443 {
444     struct sys_sem * sem;
445
446     sem = (struct sys_sem *) CHIPPlatformMemoryAlloc(sizeof(struct sys_sem));
447     if (sem != NULL)
448     {
449         sem->c = count;
450         pthread_cond_init(&(sem->cond), NULL);
451         pthread_mutex_init(&(sem->mutex), NULL);
452     }
453     return sem;
454 }
455 /*-----------------------------------------------------------------------------------*/
456 err_t sys_sem_new(struct sys_sem ** sem, u8_t count)
457 {
458     SYS_STATS_INC_USED(sem);
459     *sem = sys_sem_new_internal(count);
460     if (*sem == NULL)
461     {
462         return ERR_MEM;
463     }
464     return ERR_OK;
465 }
466 /*-----------------------------------------------------------------------------------*/
467 static u32_t cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex, u32_t timeout)
468 {
469     time_t tdiff;
470     time_t sec, usec;
471     struct timeval rtime1, rtime2;
472     struct timespec ts;
473     int retval;
474
475     if (timeout > 0)
476     {
477         /* Get a timestamp and add the timeout value. */
478         gettimeofday(&rtime1, NULL);
479         sec  = rtime1.tv_sec;
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;
485         ts.tv_sec  = sec;
486
487         retval = pthread_cond_timedwait(cond, mutex, &ts);
488
489         if (retval == ETIMEDOUT)
490         {
491             return SYS_ARCH_TIMEOUT;
492         }
493
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;
497
498         if (tdiff <= 0)
499         {
500             return 0;
501         }
502
503         return (u32_t) tdiff;
504     }
505
506     pthread_cond_wait(cond, mutex);
507
508     return 0;
509 }
510 /*-----------------------------------------------------------------------------------*/
511 u32_t sys_arch_sem_wait(struct sys_sem ** s, u32_t timeout)
512 {
513     u32_t time_needed = 0;
514     struct sys_sem * sem;
515     LWIP_ASSERT("invalid sem", (s != NULL) && (*s != NULL));
516     sem = *s;
517
518     pthread_mutex_lock(&(sem->mutex));
519     while (sem->c <= 0)
520     {
521         if (timeout > 0)
522         {
523             time_needed = cond_wait(&(sem->cond), &(sem->mutex), timeout);
524
525             if (time_needed == SYS_ARCH_TIMEOUT)
526             {
527                 pthread_mutex_unlock(&(sem->mutex));
528                 return SYS_ARCH_TIMEOUT;
529             }
530             /*      pthread_mutex_unlock(&(sem->mutex));
531                     return time_needed; */
532         }
533         else
534         {
535             cond_wait(&(sem->cond), &(sem->mutex), 0);
536         }
537     }
538     sem->c--;
539     pthread_mutex_unlock(&(sem->mutex));
540     return time_needed;
541 }
542 /*-----------------------------------------------------------------------------------*/
543 void sys_sem_signal(struct sys_sem ** s)
544 {
545     struct sys_sem * sem;
546     LWIP_ASSERT("invalid sem", (s != NULL) && (*s != NULL));
547     sem = *s;
548
549     pthread_mutex_lock(&(sem->mutex));
550     sem->c++;
551
552     if (sem->c > 1)
553     {
554         sem->c = 1;
555     }
556
557     pthread_cond_broadcast(&(sem->cond));
558     pthread_mutex_unlock(&(sem->mutex));
559 }
560 /*-----------------------------------------------------------------------------------*/
561 static void sys_sem_free_internal(struct sys_sem * sem)
562 {
563     pthread_cond_destroy(&(sem->cond));
564     pthread_mutex_destroy(&(sem->mutex));
565     CHIPPlatformMemoryFree(sem);
566 }
567 /*-----------------------------------------------------------------------------------*/
568 void sys_sem_free(struct sys_sem ** sem)
569 {
570     if ((sem != NULL) && (*sem != SYS_SEM_NULL))
571     {
572         SYS_STATS_DEC(sem.used);
573         sys_sem_free_internal(*sem);
574     }
575 }
576 #endif /* !NO_SYS */
577 /*-----------------------------------------------------------------------------------*/
578 u32_t sys_now(void)
579 {
580     struct timeval tv;
581     u32_t msec;
582     gettimeofday(&tv, NULL);
583
584     msec = (u32_t)((tv.tv_sec - starttime.tv_sec) * 1000 + (tv.tv_usec - starttime.tv_usec) / 1000);
585
586     return msec;
587 }
588 /*-----------------------------------------------------------------------------------*/
589 void sys_init(void)
590 {
591     gettimeofday(&starttime, NULL);
592 }
593 /*-----------------------------------------------------------------------------------*/
594 #if SYS_LIGHTWEIGHT_PROT
595 /** sys_prot_t sys_arch_protect(void)
596
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.
605
606 sys_arch_protect() is only required if your port is supporting an operating
607 system.
608 */
609 sys_prot_t sys_arch_protect(void)
610 {
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
613      * used. */
614     if (lwprot_thread != pthread_self())
615     {
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();
620         lwprot_count  = 1;
621     }
622     else
623         /* It is already locked by THIS thread */
624         lwprot_count++;
625     return 0;
626 }
627 /*-----------------------------------------------------------------------------------*/
628
629 /** void sys_arch_unprotect(sys_prot_t pval)
630
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
634 an operating system.
635 */
636 void sys_arch_unprotect(sys_prot_t pval)
637 {
638     LWIP_UNUSED_ARG(pval);
639     if (lwprot_thread == pthread_self())
640     {
641         if (--lwprot_count == 0)
642         {
643             lwprot_thread = (pthread_t) 0xDEAD;
644             pthread_mutex_unlock(&lwprot_mutex);
645         }
646     }
647 }
648 #endif /* SYS_LIGHTWEIGHT_PROT */
649
650 /*-----------------------------------------------------------------------------------*/
651
652 #ifndef MAX_JIFFY_OFFSET
653 #define MAX_JIFFY_OFFSET ((~0U >> 1) - 1)
654 #endif
655
656 #ifndef HZ
657 #define HZ 100
658 #endif
659
660 u32_t sys_jiffies(void)
661 {
662     struct timeval tv;
663     unsigned long sec;
664     long usec;
665
666     gettimeofday(&tv, NULL);
667     sec  = tv.tv_sec - starttime.tv_sec;
668     usec = tv.tv_usec;
669
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;
675 }
676
677 #if PPP_DEBUG
678
679 #include <stdarg.h>
680
681 void ppp_trace(int level, const char * format, ...)
682 {
683     va_list args;
684
685     (void) level;
686     va_start(args, format);
687     vprintf(format, args);
688     va_end(args);
689 }
690 #endif
691
692 #ifdef LWIP_DEBUG
693
694 unsigned char gLwIP_DebugFlags = 0;
695
696 #endif