summaryrefslogtreecommitdiffstats
path: root/stacks/lwip_stack/lwip_src/core/spl_timers.c
diff options
context:
space:
mode:
Diffstat (limited to 'stacks/lwip_stack/lwip_src/core/spl_timers.c')
-rw-r--r--stacks/lwip_stack/lwip_src/core/spl_timers.c599
1 files changed, 599 insertions, 0 deletions
diff --git a/stacks/lwip_stack/lwip_src/core/spl_timers.c b/stacks/lwip_stack/lwip_src/core/spl_timers.c
new file mode 100644
index 0000000..5e8e5d9
--- /dev/null
+++ b/stacks/lwip_stack/lwip_src/core/spl_timers.c
@@ -0,0 +1,599 @@
+/*
+*
+* Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at:
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include "opt.h"
+#include "nsfw_mem_api.h"
+#include "def.h"
+#include "sc_dpdk.h"
+#include "nstack_log.h"
+#include "nstack_securec.h"
+#include "nstack_share_res.h"
+
+#include <time.h>
+#include <signal.h>
+#include <pthread.h>
+#include <syscall.h>
+#include "nsfw_ps_api.h"
+#include "spl_timers.h"
+#include "common_mem_api.h"
+
+extern sys_thread_t g_timerThread_id;
+
+/*Since the range of the dpdk read TSC value is u64_t, it changes*/
+
+#ifndef typecheck
+#define typecheck(type, x) \
+({ type __dummy; \
+ typeof(x)__dummy2; \
+ (void)(&__dummy == &__dummy2); \
+ 1; \
+ })
+#endif
+
+#ifndef time_after_eq
+#define time_after_eq(a, b) \
+(typecheck(unsigned long, a) \
+ && typecheck(unsigned long, b) \
+ && ((long)(a) - (long)(b) >= 0))
+#endif
+
+#define MIN_TIME_PICE 50
+#define MICRO_PER_SECOND 1000
+#define NANO_PER_MICROSECOND 1000000
+#define NANO_PER_SECOND 1000000000
+
+#define PTIMER_MSG_BUFFER_SIZE 4096
+
+#define PTIMER_STATE_INACTIVE 0x00
+#define PTIMER_STATE_ENQUEUED 0x01
+#define gettid() syscall(__NR_gettid)
+
+#define TIMER_CONTEXT_NAME "TIMER_CONTEXT_NAME"
+
+static timer_t lazy_tim;
+static timer_t lazy_tim_retry;
+static struct ptimer_base ptimer;
+static sys_sem_t ptimer_lock;
+
+extern void recycle_tmr(struct ptimer_node *tmo);
+
+extern nstack_tick_info_t g_nstack_timer_tick;
+
+/*
+ ***************************
+ * rb_tree wrapper function*
+ ***************************
+ */
+NSTACK_STATIC void
+remove_ptimer(struct ptimer_node *tmo, struct ptimer_base *base)
+{
+ if (tmo == NULL)
+ {
+ NSPOL_LOGERR("input parameter tmo is null");
+ return;
+ }
+ if (!(tmo->state & PTIMER_STATE_ENQUEUED))
+ {
+ NSPOL_LOGWAR(TIMERS_DEBUG | LWIP_DBG_LEVEL_WARNING,
+ "the timer state is: PTIMER_STATE_INACTIVE, no need to remove!");
+ return;
+ }
+
+ if (base->first == &tmo->node)
+ {
+ base->first = rb_next(&tmo->node);
+ }
+
+ rb_erase(&tmo->node, &base->active);
+
+ tmo->state = PTIMER_STATE_INACTIVE;
+}
+
+NSTACK_STATIC struct ptimer_node *search_ptimer(struct ptimer_msg *msg)
+{
+ if (msg == NULL)
+ {
+ NSPOL_LOGERR("input parameter msg is null");
+ return NULL;
+ }
+ if (msg->node)
+ {
+ return msg->node;
+ }
+
+ return NULL;
+
+}
+
+err_t del_ptimer(struct ptimer_msg * msg)
+{
+ struct ptimer_node *tmo;
+
+ tmo = search_ptimer(msg);
+ if (tmo)
+ {
+ remove_ptimer(tmo, &ptimer);
+ NSPOL_LOGDBG(TIMERS_DEBUG, "del]thread=%u,ptimer_node=%p", tmo->index,
+ tmo);
+ return ERR_OK;
+ }
+
+ NSPOL_LOGERR("ptime_node not found!!");
+ return ERR_VAL;
+}
+
+/*
+ * Ptimer inserted into rb_tree
+ * @param node: the ptimer node pointer
+ * @param base: the ptimer root_base pointer
+ */
+NSTACK_STATIC void
+enqueue_ptimer(struct ptimer_node *tmo, struct ptimer_base *base)
+{
+ struct rb_node **linknode;
+ struct rb_node *parent = NULL;
+ struct ptimer_node *entry;
+ int leftmost = 1;
+ if (tmo == NULL || base == NULL)
+ {
+ NSPOL_LOGERR("input parameter is null");
+ return;
+ }
+
+ if ((tmo->state & PTIMER_STATE_ENQUEUED))
+ {
+ NSPOL_LOGWAR(TIMERS_DEBUG | LWIP_DBG_LEVEL_WARNING,
+ "the timer state is: PTIMER_STATE_ENQUEUED");
+ return;
+ }
+
+ linknode = &base->active.rb_node;
+ while (*linknode)
+ {
+ parent = *linknode;
+ entry = rb_entry(parent, struct ptimer_node, node);
+ //XXX: do by the equal case is all of price of the large case
+ if (time_after_eq(entry->abs_nsec, tmo->abs_nsec))
+ {
+ linknode = &(*linknode)->rb_left;
+ }
+ else
+ {
+ linknode = &(*linknode)->rb_right;
+ leftmost = 0;
+ }
+ }
+
+ /*
+ * Insert the timer to the rb_tree and check whether it
+ * replaces the first pending timer
+ */
+ if (leftmost)
+ {
+ base->first = &tmo->node;
+ }
+
+ rb_link_node(&tmo->node, parent, linknode);
+ rb_insert_color(&tmo->node, &base->active);
+ NSPOL_LOGDBG(TIMERS_DEBUG, "enqueue]thread=%u,ptimer_node=%p", tmo->index,
+ tmo);
+ tmo->state |= PTIMER_STATE_ENQUEUED;
+}
+
+void launch_tmr(timer_t * tim, u64_t nsec)
+{
+ struct itimerspec vtim;
+
+ vtim.it_value.tv_sec = (nsec) / NANO_PER_SECOND;
+ vtim.it_value.tv_nsec = (nsec) % NANO_PER_SECOND;
+ vtim.it_interval.tv_sec = 0;
+ vtim.it_interval.tv_nsec = 0;
+
+ if (timer_settime(*tim, 0, &vtim, NULL) < 0)
+ {
+ NSPOL_LOGERR("add_ptimer:timer_settime failed");
+ }
+
+}
+
+/*
+ * add ptimer to rb_tree
+ * @param tmo: the ptimer node pointer
+ */
+void add_ptimer(struct ptimer_node *tmo)
+{
+ if (tmo == NULL)
+ {
+ NSPOL_LOGERR("input parameter is null");
+ return;
+ }
+ enqueue_ptimer(tmo, &ptimer);
+
+ if (ptimer.first == &tmo->node)
+ {
+ launch_tmr(&lazy_tim, tmo->info.msec * NANO_PER_MICROSECOND);
+ }
+}
+
+#if 1
+/*
+ * cond signal ,send a ptimer message
+ * @param type: the message type
+ * @param handler: timeout handler
+ * @param node: the ptimer node pointer
+ */
+void
+regedit_ptimer(enum msg_type Type, sys_timeout_handler handler,
+ struct ptimer_node *node)
+{
+ (void) handler;
+ (void) pthread_mutex_lock(&ptimer.lock);
+ if (ptimer.tail == NULL)
+ {
+ (void) pthread_mutex_unlock(&ptimer.lock);
+ NSPOL_LOGERR("ptimer.tail is null");
+ free(node);
+ node = NULL;
+ return;
+ }
+ ptimer.tail->msg_type = Type;
+ ptimer.tail->node = node;
+ ptimer.tail = ptimer.tail->next;
+ if (ptimer.head == ptimer.tail)
+ {
+ (void) pthread_mutex_unlock(&ptimer.lock);
+ NSPOL_LOGERR("ptimer.head equal to ptimer.tail");
+ return;
+ }
+
+ (void) pthread_kill(g_timerThread_id, SIGRTMIN + 2);
+
+ (void) pthread_mutex_unlock(&ptimer.lock);
+ return;
+}
+#endif
+/*
+ * deal with the timeout signal
+ *
+ */
+void deal_timeout_sig(void)
+{
+ struct ptimer_node *tmo;
+ struct timespec now;
+ unsigned long abs_nsec;
+ err_t err;
+ int retval;
+ if (ptimer.first == NULL)
+ {
+ return;
+ }
+ tmo = rb_entry(ptimer.first, struct ptimer_node, node);
+ retval = clock_gettime(CLOCK_MONOTONIC, &now);
+ if (0 != retval)
+ {
+ NSPOL_LOGERR("clock_gettime failed]retval=%d,errno=%d", retval,
+ errno);
+ }
+ abs_nsec = now.tv_sec * NANO_PER_SECOND + now.tv_nsec;
+
+ // deal with all timeout point
+ while (time_after_eq(abs_nsec, tmo->abs_nsec))
+ {
+ remove_ptimer(tmo, &ptimer);
+
+ if (tmo->info.flags & PTIMER_ONESHOT)
+ {
+ }
+ else
+ {
+ //re-entry periodic ptimer
+ tmo->abs_nsec = now.tv_sec * NANO_PER_SECOND + now.tv_nsec
+ + tmo->info.msec * NANO_PER_MICROSECOND;
+ add_ptimer(tmo);
+ }
+
+ //send timeout message
+ NSPOL_LOGDBG(INTERRUPT_DEBUG,
+ "ptimer happened to thread_index]index=%u", tmo->index);
+ if ((err = ltt_apimsg(tmo->info._phandle, (void *) tmo)))
+ {
+ NSPOL_LOGWAR(TIMERS_DEBUG | LWIP_DBG_LEVEL_WARNING,
+ "send timeout message failed!]errno=%d", err);
+ }
+
+ if (ptimer.first == NULL)
+ {
+ NSPOL_LOGERR("deal_timeout_sig: ptimer.first == NULL!!");
+ return;
+ }
+ tmo = rb_entry(ptimer.first, struct ptimer_node, node);
+ }
+
+ if (tmo->abs_nsec <= abs_nsec)
+ {
+ NSPOL_LOGERR("tmo->abs_nsec is smaller than abs_nsec");
+ return;
+ }
+
+ NSPOL_LOGDBG(TIMERS_DEBUG, "TIMERSIGNAL : Launch timer for]time=%ul",
+ tmo->abs_nsec - abs_nsec);
+ launch_tmr(&lazy_tim, tmo->abs_nsec - abs_nsec); //timer interupted eveny 50ms instand by tmo->abs_nsec
+}
+
+/*
+ * timeout signal handle function
+ * @param v: unused argument
+ */
+/*ptimer is already protected and used*/
+
+NSTACK_STATIC void timeout_sigaction(int sig)
+{
+ (void) sig;
+ if (!sys_arch_sem_trywait(&ptimer_lock))
+ {
+ launch_tmr(&lazy_tim_retry,
+ (MIN_TIME_PICE / 5) * NANO_PER_MICROSECOND);
+ return;
+ }
+
+ deal_timeout_sig();
+
+ sys_sem_signal(&ptimer_lock);
+
+ return;
+}
+
+/*
+ * initialize the ptimer buffer and timing mechanism
+ */
+err_t init_ptimer(void)
+{
+ int i, retval;
+ struct sigevent timer_event;
+ struct sigevent timer_event1;
+ struct ptimer_msg *ptr;
+
+ if (pthread_mutex_init(&ptimer.lock, NULL))
+ {
+ NSPOL_LOGERR("pthread_mutex_init failed");
+ return ERR_MEM;
+ }
+ /*codex fix */
+ if (ERR_MEM == sys_sem_new(&ptimer_lock, 1))
+ {
+ NSPOL_LOGERR("init_ptimer: sys_sem_new failure");
+ return ERR_MEM;
+ }
+
+ ptimer.active.rb_node = NULL;
+ ptimer.first = NULL;
+
+ ptr =
+ (struct ptimer_msg *) malloc(PTIMER_MSG_BUFFER_SIZE *
+ sizeof(struct ptimer_msg));
+ if (!ptr)
+ {
+ NSPOL_LOGERR("init_ptimer: malloc ptimer buffer failed!");
+ return ERR_MEM;
+ }
+
+ int ret =
+ memset_s(ptr, (PTIMER_MSG_BUFFER_SIZE * sizeof(struct ptimer_msg)),
+ 0, (PTIMER_MSG_BUFFER_SIZE * sizeof(struct ptimer_msg)));
+ if (EOK != ret)
+ {
+ free(ptr);
+ NSPOL_LOGERR("init_ptimer: MEMSET_S ptimer buffer failed]ret=%d",
+ ret);
+ return ERR_MEM;
+ }
+
+ for (i = 0; i < PTIMER_MSG_BUFFER_SIZE - 1; i++)
+ {
+ ptr[i].next = &ptr[(i + 1)];
+ ptr[(i + 1)].prev = &ptr[i];
+ }
+
+ ptr[i].next = &ptr[0];
+ ptr[0].prev = &ptr[i];
+ ptimer.head = ptimer.tail = &ptr[0];
+ retval =
+ memset_s(&timer_event, sizeof(struct sigevent), 0,
+ sizeof(struct sigevent));
+ if (EOK != retval)
+ {
+ free(ptr);
+ ptr = NULL;
+ NSPOL_LOGERR("MEMSET_S failed]ret=%d", retval);
+ return ERR_VAL;
+ }
+ timer_event.sigev_notify = SIGEV_SIGNAL;
+ timer_event.sigev_signo = SIGRTMIN;
+ timer_event.sigev_value.sival_ptr = (void *) &lazy_tim;
+ timer_event1 = timer_event;
+ timer_event1.sigev_value.sival_ptr = (void *) &lazy_tim_retry;
+
+ if (timer_create(CLOCK_MONOTONIC, &timer_event, &lazy_tim) < 0)
+ {
+ free(ptr);
+ ptr = NULL;
+ NSPOL_LOGERR("ptimer_init: timer_create failed!");
+ return ERR_VAL;
+ }
+
+ if (timer_create(CLOCK_MONOTONIC, &timer_event1, &lazy_tim_retry) < 0)
+ {
+ free(ptr);
+ ptr = NULL;
+ NSPOL_LOGERR("ptimer_init: timer_create failed!");
+ return ERR_VAL;
+ }
+
+ return ERR_OK;
+}
+
+NSTACK_STATIC err_t process_timeout_msg(struct ptimer_msg * msg)
+{
+ struct ptimer_node *tmo = msg->node;
+ struct timespec now;
+
+ switch (msg->msg_type)
+ {
+ case SYS_PTIMEROUT_MSG:
+ if (tmo)
+ {
+ int retval = clock_gettime(CLOCK_MONOTONIC, &now);
+ if (0 != retval)
+ {
+ NSPOL_LOGERR("clock_gettime failed]retval=%d,errno=%d",
+ retval, errno);
+ }
+ tmo->abs_nsec = now.tv_sec * NANO_PER_SECOND + now.tv_nsec
+ + tmo->info.msec * NANO_PER_MICROSECOND;
+ add_ptimer(tmo);
+ }
+ else
+ {
+ NSPOL_LOGERR("process_timeout_msg: rb_node is NULL!");
+ return ERR_MEM;
+ }
+
+ break;
+ case SYS_UNPTIMEROUT_MSG:
+ if (del_ptimer(msg) != ERR_OK)
+ {
+ NSPOL_LOGERR
+ ("process_timeout_msg: can not find the timeout event(oops)!");
+ }
+
+ break;
+ default:
+ NSPOL_LOGERR
+ ("process_timeout_msg: oops! lwip timeout_thread receive unacquainted message!");
+ break;
+ }
+
+ return ERR_OK;
+}
+
+void ptimer_thread(void *arg)
+{
+ LWIP_UNUSED_ARG(arg);
+ int sig, ret = -1;
+ sigset_t waitset;
+ sigset_t oset;
+ struct ptimer_msg *msg;
+
+ if (0 != sigemptyset(&waitset))
+ {
+ NSTCP_LOGERR("sigemptyset function call error");
+ return;
+ }
+
+ if (0 != sigaddset(&waitset, SIGRTMIN))
+ {
+ NSTCP_LOGERR("sigaddset function call error");
+ return;
+ }
+
+ if (0 != sigaddset(&waitset, SIGRTMIN + 2))
+ {
+ NSTCP_LOGERR("sigaddset function call error");
+ return;
+ }
+
+ (void) pthread_sigmask(SIG_BLOCK, &waitset, &oset);
+
+ (void) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ (void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+ NSPOL_LOGDBG(TIMERS_DEBUG, "ptimer: init done !");
+
+ if (!g_nstack_timer_tick.tick_ptr)
+ {
+ NSTCP_LOGERR("g_nstack_timer_tick not inited");
+ return;
+ }
+ (void) gettimeofday(&g_nstack_timer_tick.ref_time, NULL);
+ g_nstack_timer_tick.interval = 100;
+ *g_nstack_timer_tick.tick_ptr = 0;
+ g_nstack_timer_tick.ref_tick = 0;
+ while (1)
+ {
+ ret = sigwait(&waitset, &sig);
+ (void) nsfw_thread_chk(); // will only return TRUE, no need to check return value
+ if (ret != -1)
+ {
+ /* for timer expirt handle */
+ if (SIGRTMIN == sig)
+ {
+ timeout_sigaction(sig);
+ continue;
+ }
+ }
+ else
+ {
+ continue;
+ }
+
+ while (1)
+ {
+ (void) pthread_mutex_lock(&ptimer.lock);
+ if (ptimer.head == ptimer.tail)
+ {
+ (void) pthread_mutex_unlock(&ptimer.lock);
+ break;
+ }
+
+ msg = ptimer.head;
+ ptimer.head = ptimer.head->next;
+ (void) pthread_mutex_unlock(&ptimer.lock);
+
+ sys_arch_sem_wait(&ptimer_lock, 0);
+
+ if (process_timeout_msg(msg) != ERR_OK)
+ {
+ NSPOL_LOGERR("oops: ptimer_thread panic!");
+ }
+
+ sys_sem_signal(&ptimer_lock);
+ }
+ }
+}
+
+void timeout_phandler(void *act, void *arg)
+{
+ struct ptimer_node *tmo = arg;
+ if (act == NULL)
+ {
+ NSPOL_LOGERR("input parameter arg is null");
+ return;
+ }
+
+ NSPOL_LOGINF(TIMERS_DEBUG, "Timer expire @timeout_phandler Handle %p",
+ tmo->info._phandle);
+ if (tmo->info.flags & PTIMER_ONESHOT)
+ {
+ sys_timeout_handler handle = act;
+ handle(tmo->info.ctx);
+ return;
+ }
+ else
+ {
+ NSPOL_LOGINF(TIMERS_DEBUG,
+ "Timer expire error @timeout_phandler Handle %p",
+ tmo->info._phandle);
+ }
+}