新版本的glib支持使用外部的事件循环代替内部的poll,这篇文章使用的glib版本是V2.72.0, 理解还很粗浅,但是demo能跑起来,还需要再详细研究一下参考的两个链接,多线程下使用及效率是怎样的都还不清楚。
1、新API
通过新的API g_main_context_new_with_flags 及新变量G_MAIN_CONTEXT_FLAGS_OWNERLESS_POLLING可以创建一个无主的poll,然后通过glib的一套API可以实现自己的事件循环。ubuntu18下的demo:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <glib.h>
#include <sys/epoll.h>
static GMainContext *watchdog_context = NULL;
int num = 0;
static gboolean cb_check(gpointer user_data)
{
printf("In cb_check %d \n", num);
}
char* name = "ori";
static gpointer cb_watchdog(gpointer user_data)
{
num = 1;
GMainLoop *loop = (GMainLoop *) user_data;
GMainContext *watchdog_context = g_main_loop_get_context(loop);
GSource *timeout_source;
timeout_source = g_timeout_source_new_seconds(2);
g_source_set_callback(timeout_source, cb_check, watchdog_context, (gpointer)name);
g_source_attach(timeout_source, watchdog_context);
g_source_unref(timeout_source);
printf("Sessions watchdog started\n");
g_main_loop_run(loop);
printf("Sessions watchdog stopped\n");
return NULL;
}
void test_ori_glib_event_loop()
{
/* Start the sessions timeout watchdog */
watchdog_context = g_main_context_new();
GError *error = NULL;
GMainLoop *watchdog_loop = g_main_loop_new(watchdog_context, FALSE);
GThread *watchdog = g_thread_try_new("timeout watchdog", &cb_watchdog, watchdog_loop, &error);
if(error != NULL)
{
printf("Got error %d (%s) trying to start sessions timeout watchdog...\n",
error->code, error->message ? error->message : "??");
g_error_free(error);
exit(1);
}
}
unsigned short glib_event_2_epoll(unsigned short glib_event)
{
unsigned short ret = 0;
if (glib_event & G_IO_IN)
ret |= EPOLLIN;
if (glib_event & G_IO_OUT)
ret |= EPOLLOUT;
if (glib_event & G_IO_PRI)
ret |= EPOLLPRI;
if (glib_event & G_IO_HUP)
ret |= EPOLLHUP;
if (glib_event & G_IO_NVAL)
ret |= EPOLLERR;
return ret;
}
unsigned short epoll_event_2_glib(unsigned short epoll_event)
{
unsigned short ret = 0;
if (epoll_event & EPOLLIN)
ret |= G_IO_IN;
if (epoll_event & EPOLLOUT)
ret |= G_IO_OUT ;
if (epoll_event & EPOLLPRI)
ret |= G_IO_PRI;
if (epoll_event & EPOLLHUP)
ret |= G_IO_HUP;
if (epoll_event & EPOLLERR)
ret |= G_IO_NVAL;
return ret;
}
#define MAX_EVENTS (4096)
int ev_poll(GPollFD *fds,
guint nfds,
gint timeout)
{
GPollFD *f = NULL;
int epollfd = -1;
struct epoll_event ev;
int ret = 0;
int max_events = nfds;
struct epoll_event epoll_events[MAX_EVENTS];
for (f = fds; f < &fds[nfds]; ++f)
{
if (f->fd >= 0)
{
if(epollfd == -1)
{
epollfd = epoll_create1(EPOLL_CLOEXEC);
if ( epollfd == -1 )
{
perror( "epoll_create1" );
continue;
}
}
ev.events = f->events;//glib_event_2_epoll(f->events);
ev.data.fd = f->fd;
if( epoll_ctl(epollfd, EPOLL_CTL_ADD, f->fd, &ev) == -1 )
{
perror( "epoll_ctl: listen_sock" );
continue;
}
}
}
nfds = epoll_wait( epollfd, epoll_events, MAX_EVENTS, 10 );
if(nfds > 0)
{
//unsigned short events = event[i].events;
struct epoll_event *ev = NULL;
for (ev = epoll_events; ev < &epoll_events[nfds]; ++ev)
{
f->revents = 0;
if (f->fd >= 0)
{
f->revents = ev->events;//epoll_event_2_glib(ev->events);
}
}
}
else
{
perror( "epoll_wait" );
return 0;
}
if(epollfd != -1)
{
close(epollfd);
}
return nfds;
}
char* evname = "ev_ori";
/* epoll实现的事件侦听及处理 */
void test_ev_glib_event_loop()
{
num = 2;
/* Start the sessions timeout watchdog */
GMainContext *ctx = g_main_context_new_with_flags (G_MAIN_CONTEXT_FLAGS_OWNERLESS_POLLING);
g_main_context_push_thread_default (ctx);
GPollFD fds[20];
gint fds_size;
gint max_priority;
GSource *source = NULL;
GSource *timeout_source;
timeout_source = g_timeout_source_new_seconds(2);
g_source_set_callback(timeout_source, cb_check, ctx, (gpointer)evname);
g_source_attach(timeout_source, ctx);
g_source_unref(timeout_source);
for(;;)
{
gboolean ready_to_dispatch = g_main_context_prepare (ctx, &max_priority);
gint timeout, nready;
fds_size = g_main_context_query (ctx, max_priority, &timeout, fds, G_N_ELEMENTS (fds));
//nready = g_poll (fds, fds_size, /*timeout=*/0);
nready = ev_poll (fds, fds_size, /*timeout=*/0);
if (!ready_to_dispatch && nready == 0)
{
if (timeout == -1)
break;
else
g_usleep (timeout * 1000);
}
if(fds_size == 1)
printf("events %d \n", fds[0].events);
printf("events G_IO_IN[%d] G_IO_OUT[%d] G_IO_PRI[%d]\n", G_IO_IN, G_IO_OUT, G_IO_PRI);
ready_to_dispatch = g_main_context_check (ctx, max_priority, fds, fds_size);
if (ready_to_dispatch)
g_main_context_dispatch (ctx);
}
g_assert_cmpint (g_poll (fds, fds_size, 0), >, 0);
g_main_context_unref (ctx);
}
int main()
{
//test_ori_glib_event_loop();
test_ev_glib_event_loop();
while(1)
{
sleep(1);
}
return 0;
}
编译
gcc -o demo_glib main.c -lpthread `pkg-config --cflags glib-2.0` `pkg-config --libs glib-2.0`
2、参考
《1》、Pluggable event loop backends (epoll support) 《2》、Add g_main_context_new_with_flags() and ownerless polling option
|