新版本glib使用epoll代替poll

7 篇文章 1 订阅
7 篇文章 5 订阅

新版本的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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值