Files
TAIXIN/sdk/lib/net/eloop/eloop.c

545 lines
12 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**@file eloop.c
* @author 何凱帆
* @brief 基於socket的event loop服務
* @details 提供基於socket的event loop服務
*
* 系統依賴:
* - time
* - socket
* 這些依賴在plat-cfg.h的system time config和socket config中解決單獨移植時可從中抽取
*
* 統一使用list.h來管理雙向鏈表
*/
#include "sys_config.h"
#include "typesdef.h"
#include "list.h"
#include "lib/net/eloop/eloop.h"
#include "osal/irq.h"
#include <k_api.h>
//#include "osal/osal_time.h"
#define eloop_dbg(fmt, ...) _os_printf("%s:%d::"fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define eloop_err(fmt, ...) _os_printf("%s:%d::"fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#ifndef INVALID_SOCKET
#define INVALID_SOCKET ~0
#endif
#if ELOOP_WAKEUP_BY_LOOPBACK
static int global_loopback_socket;
#endif
static uint8_t global_loopback_flag = 0; //读标志,防止自己唤醒过多,保证尽量多个线程也是只是唤醒一次
//#include "debug.h"
static void eloop_wakeup(void);
static struct eloop_state els;
/*******************************************************************************
* time
******************************************************************************/
int time_diff(eloop_time_ref* tr_start, eloop_time_ref* tr_end)
{
return (*tr_end) - (*tr_start);
}
int time_ago(eloop_time_ref* tr)
{
eloop_time_ref now;
now = get_time_now();
return time_diff(&now,tr);
}
void time_now(eloop_time_ref* tr)
{
*tr = get_time_now();
}
//单位是ms
unsigned int get_time_now()
{
unsigned int now_time;
now_time = os_jiffies();
return now_time;
}
void time_add(eloop_time_ref* tr, int msec)
{
*tr += (msec);
}
void time_future(eloop_time_ref* tr, int msec)
{
*tr = get_time_now();
time_add(tr,msec);
}
/*******************************************************************************
* eloop
******************************************************************************/
static struct event* eloop_new_event(event_callback f, void* d)
{
struct event* e;
e = (struct event*)malloc(sizeof(struct event));
if(!e)
{
eloop_err("malloc fail\n");
return e;
}
INIT_LIST_HEAD(&e->list);
e->type = 0;
e->flags = 0;
e->func = f;
e->data = d;
return e;
}
static void eloop_strip_events(struct list_head* list)
{
struct list_head* pos, *n;
struct event* e;
list_for_each_safe(pos, n, list)
{
e = list_entry(pos, struct event, list);
if(e->flags & EVENT_F_REMOVE) {
list_del_init(pos);
free(e); // todo: 要確定誰來負責釋放空間
}
}
}
//轮询wait事件(没有添加到对应列表的事件),这里只是管添加,不管事件的状态
static int eloop_wait_events(struct list_head* list)
{
struct list_head* pos, *n;
struct event* e;
int count = 0;
uint32_t flag;
list_for_each_safe(pos, n, list)
{
e = list_entry(pos, struct event, list);
flag = disable_irq();
list_del_init(pos);
enable_irq(flag);
count++;
switch(e->type)
{
case EVENT_TIME:
list_add(&e->list, &els.times);
break;
case EVENT_FD:
list_add(&e->list, &els.fds);
break;
case EVENT_ALWAYS:
list_add(&e->list, &els.always);
break;
default:
eloop_err("%s:%d err\n",__FUNCTION__,__LINE__);
break;
}
}
return count;
}
void eloop_resched_event(EVT_HDL ev, eloop_time_ref* tr)
{
struct event* e = (struct event*)ev;
if(tr)
e->ev.time.fire = *tr;
else if(e->flags & EVENT_F_ENABLED)
time_add(&e->ev.time.fire, e->ev.time.ival);
else
time_future(&e->ev.time.fire, e->ev.time.ival);
e->flags &= ~EVENT_F_REMOVE;
//e->flags |= EVENT_F_ENABLED;
}
void set_event_time(void *d,int msec)
{
struct event* e = (struct event*)d;
e->ev.time.ival = msec;
}
EVT_HDL eloop_add_timer(int msec, unsigned int flags, event_callback f, void* d)
{
struct event* e;
e = eloop_new_event(f, d);
if(!e)
{
return e;
}
e->type = EVENT_TIME;
e->flags = flags;
e->ev.time.ival = msec;
time_now(&e->ev.time.fire);
eloop_resched_event(e, NULL);
uint32_t flag = disable_irq();
list_add(&e->list, &els.wait);
enable_irq(flag);
eloop_wakeup();
return e;
}
/****************************************************************************************
arg:
t:执行的时间,类似闹钟
注意:调用该函数,默认就是EVENT_F_ONESHOT,但是是否启动通过flags来配置
******************************************************************************************/
EVT_HDL eloop_add_alarm(eloop_time_ref t, unsigned int flags, event_callback f, void* d)
{
struct event* e;
eloop_time_ref timer = t;
e = eloop_new_event(f, d);
if(!e)
{
return e;
}
e->type = EVENT_TIME;
e->flags = flags | EVENT_F_ONESHOT;
e->ev.time.ival = 0;
eloop_resched_event(e, &timer);
uint32_t flag = disable_irq();
list_add(&e->list, &els.wait);
enable_irq(flag);
eloop_wakeup();
return e;
}
EVT_HDL eloop_add_fd(SOCK_HDL fd, int write, unsigned int flags, event_callback f, void* d)
{
struct event* e;
e = eloop_new_event(f, d);
if(!e)
{
return e;
}
e->type = EVENT_FD;
e->flags = flags ;
e->ev.fd.fd = fd;
e->ev.fd.write = write;
uint32_t flag = disable_irq();
list_add(&e->list, &els.wait);
enable_irq(flag);
eloop_wakeup();
return e;
}
EVT_HDL eloop_add_fd_init(SOCK_HDL fd, int write, unsigned int flags, event_callback f, void* d)
{
struct event* e;
e = eloop_new_event(f, d);
if(!e)
{
return e;
}
e->type = EVENT_FD;
e->flags = flags;
e->ev.fd.fd = fd;
e->ev.fd.write = write;
uint32_t flag = disable_irq();
list_add(&e->list, &els.wait);
enable_irq(flag);
return e;
}
EVT_HDL eloop_add_always(unsigned int flags, event_callback f, void* d)
{
struct event* e;
e = eloop_new_event(f, d);
if(!e)
{
return e;
}
e->type = EVENT_ALWAYS;
e->flags = flags | EVENT_F_ENABLED;
uint32_t flag = disable_irq();
list_add(&e->list, &els.wait);
enable_irq(flag);
eloop_wakeup();
return e;
}
void eloop_remove_event(EVT_HDL ev)
{
struct event* e = (struct event*)ev;
e->flags |= EVENT_F_REMOVE;
e->flags &= ~(EVENT_F_RUNNING | EVENT_F_ENABLED);
eloop_wakeup();
}
void eloop_set_event_interval(EVT_HDL ev, int msec)
{
struct event* e = (struct event*)ev;
e->ev.time.ival = msec;
if(e->flags & EVENT_F_ENABLED)
eloop_resched_event(e, NULL);
}
void eloop_set_event_enabled(EVT_HDL ev, int enabled)
{
struct event* e = (struct event*)ev;
if(enabled)
e->flags |= EVENT_F_ENABLED;
else
e->flags &= ~EVENT_F_ENABLED;
eloop_wakeup();
}
int eloop_get_event_enabled(EVT_HDL ev)
{
struct event* e = (struct event*)ev;
return e->flags & EVENT_F_ENABLED ? 1 : 0;
}
void eloop_exit(void)
{
els.end_loop = 1;
}
int eloop_wakeup_init(void);
void eloop_init(void)
{
eloop_dbg("start\r\n");
INIT_LIST_HEAD(&els.times);
INIT_LIST_HEAD(&els.fds);
INIT_LIST_HEAD(&els.always);
INIT_LIST_HEAD(&els.wait);
els.end_loop = 0;
/* */
// if(osal_socket_startup()) {
// p_err("Socket startups error!");
// return;
// }
eloop_wakeup_init();
}
void user_eloop_run()
{
time_ref t, *st;
struct event* e;
int diff, nexttime = 0, highfd, ret;
fd_set rfds, wfds;
int count = 0;
els.end_loop = 0;
eloop_dbg("run\r\n");
do {
struct list_head* pos, *n;
global_loopback_flag = 0;
st = NULL;
//如果有需要添加到其他list的,就将nexttime设置为0,需要立刻轮询一下
count = eloop_wait_events(&els.wait);
if(count)
{
nexttime = 0;
}
/* check how long the timeout should be */
list_for_each_safe(pos, n, &els.times)
{
e = list_entry(pos, struct event, list);
if(e->flags & EVENT_F_ENABLED) {
diff = time_ago(&e->ev.time.fire);
if(diff < 1)
diff = 0;
if(!st || diff < nexttime)
nexttime = diff;
st = &t;
e->flags |= EVENT_F_RUNNING;
} else
e->flags &= ~EVENT_F_RUNNING;
}
list_for_each_safe(pos, n, &els.always)
{
e = list_entry(pos, struct event, list);
if(e->flags & EVENT_F_ENABLED) {
st = &t;
nexttime = 0;
e->flags |= EVENT_F_RUNNING;
} else
e->flags &= ~EVENT_F_RUNNING;
}
if(st) {
st->tv_sec = nexttime / 1000;
st->tv_usec = (nexttime % 1000) * 1000;
}
FD_ZERO(&rfds);
FD_ZERO(&wfds);
highfd = -1;
/* This is all so ugly... It should use poll() eventually. */
list_for_each_safe(pos, n, &els.fds)
{
e = list_entry(pos, struct event, list);
if(e->flags & EVENT_F_ENABLED) {
FD_SET(e->ev.fd.fd, e->ev.fd.write ? &wfds : &rfds);
if(e->ev.fd.fd > highfd)
highfd = e->ev.fd.fd;
e->flags |= EVENT_F_RUNNING;
} else
e->flags &= ~EVENT_F_RUNNING;
}
ret = select(highfd + 1, &rfds, &wfds, NULL, st);
global_loopback_flag = 1;
list_for_each_safe(pos, n, &els.times)
{
e = list_entry(pos, struct event, list);
if(!(e->flags & EVENT_F_RUNNING))
continue;
if(els.end_loop)
break;
diff = time_ago(&e->ev.time.fire);
if(diff < 1) {
if(!(e->flags & EVENT_F_ONESHOT))
eloop_resched_event(e, NULL);
else
e->flags |= EVENT_F_REMOVE;
(*e->func)(e, e->data);
}
}
list_for_each_safe(pos, n, &els.always)
{
e = list_entry(pos, struct event, list);
if(!(e->flags & EVENT_F_RUNNING))
continue;
if(els.end_loop)
break;
if(e->flags & EVENT_F_ONESHOT)
e->flags |= EVENT_F_REMOVE;
(*e->func)(e, e->data);
}
if(ret > 0)
list_for_each_safe(pos, n, &els.fds)
{
e = list_entry(pos, struct event, list);
if(!(e->flags & EVENT_F_RUNNING))
continue;
if(els.end_loop)
break;
if(FD_ISSET(e->ev.fd.fd, e->ev.fd.write ? &wfds : &rfds)) {
if(e->flags & EVENT_F_ONESHOT)
e->flags |= EVENT_F_REMOVE;
(*e->func)(e, e->data);
}
}
eloop_strip_events(&els.times);
eloop_strip_events(&els.fds);
eloop_strip_events(&els.always);
} while(!els.end_loop );
}
#if ELOOP_WAKEUP_BY_LOOPBACK
struct udp_loopback
{
int version;//版本号,版本一致才能正常接收
int port;//端口号
unsigned int size;
int crc;//保留crc校验机制
};
static void eloop_wakeup_read(struct event *ei, void *d)
{
int socket = (int)d;
struct udp_loopback loopback;
struct sockaddr_in remote_addr;
socklen_t retval = (sizeof(struct sockaddr_in));
recvfrom(socket, (char*)&loopback, sizeof(struct udp_loopback), 0,(struct sockaddr *) &remote_addr, &retval);
global_loopback_flag = 0;
}
int eloop_wakeup_init(void)
{
int err;
int t_socket;
struct sockaddr_in listenAddr;
struct sockaddr_in connect_addr;
socklen_t namelen = sizeof(connect_addr);
memset(&listenAddr, 0, sizeof(struct sockaddr_in));
listenAddr.sin_family = AF_INET;
listenAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
listenAddr.sin_port = htons(0);
t_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (t_socket == INVALID_SOCKET)
{
eloop_err("socket error !");
return 1;
}
err = bind(t_socket, (struct sockaddr*) &listenAddr, sizeof(struct sockaddr_in));
global_loopback_socket = t_socket;
getsockname( t_socket, (struct sockaddr *)&connect_addr, &namelen );
connect( t_socket, (struct sockaddr *)&connect_addr,sizeof( connect_addr ) );
eloop_add_fd_init( t_socket, EVENT_READ, EVENT_F_ENABLED, (void*)eloop_wakeup_read, (void*)t_socket );
return 0;
}
static void eloop_wakeup(void)
{
struct udp_loopback loopback;
if(global_loopback_flag)
{
return;
}
global_loopback_flag = 1;
//sendto(global_loopback_socket, (char*)&loopback, sizeof(loopback), 0, (struct sockaddr*)&global_loop_addr, sizeof (global_loop_addr));
send(global_loopback_socket, (char*)&loopback, sizeof(loopback), 0);
}
#else /* ELOOP_WAKEUP_BY_LOOPBACK */
// loopback機制不可用的話採用定時事件來喚醒
static void eloop_wakeup_read(EVT_HDL e, void* d)
{
_os_printf ("eloop wakeup\r\n");
}
int eloop_wakeup_init(void)
{
EVT_HDL e;
e = eloop_add_timer (5000, EVENT_F_ENABLED, eloop_wakeup_read, NULL);
}
static void eloop_wakeup(void) {}
#endif /* ELOOP_WAKEUP_BY_LOOPBACK */