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

545 lines
12 KiB
C
Raw Normal View History

/**@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 */