select() vs pselect()

http://jineshkj.wordpress.com/2008/02/02/why-pselect/

All this time I had thought pselect() is simply a luxury, a waste of system call entry, something that i never expected from open source community. I should have blamed POSIX for introducing such a one, but, why would any open source operating system implement it. If you ever wanted to block a set of signal, just calling sigprocmask() before select would be sufficient.

This is where the need for ‘!’ operator helps. ie, right, pselect() is not meant for blocking signals, but rather to unblock them ;-) . Such a requirement arises out in event loops, which normally anyone would expect to be implemented as:

while(1)
{

if(need_to_quit)

break;

if(select(…) == -1)
{

if(errno == EINTR)

continue;

}

}

and in the SIGQUIT signal handler you would write :

sigquit_handler()
{

need_to_quit = 1;

}

The problem with such an approach is that if the event comes and get handled after the global volatile(挥发性的) variable ‘need_to_quit’ is checked, but before select() is called, then the event loop would behave as if it has lost the event, and the select() will block till we again get an event.

POSIX recommends the solution to be to use pselect(). Now, how to use it would be what you are thinking, so, here it goes:

step 1 : you block all signals and save the current sigmask
step 2 : check the event condition and do what is required
step 3 : call pselect() and pass it a signal mask to enable all the signals that would provide you the events. when pselect() returns, it will restore the sigmask it had when it was entered(ie, here all the signals masked).
step 4 : you restore the old signal mask

thats it, the race condition is solved. This now makes sure that any signal that comes after checking the variable will be received only after select() has entered. You might now be wondering why we can not do the same thing by writing our own function than a system call. Well here is how it would look :

pselect(..)
{

sigprocmask(.., &new_mask, &old_mask); // enable the signals to be received

select();

sigprocmask(.., &old_mask, null);

}

YES.. If you have noticed, this still gives you a race condition when a signal arrives before select() is called and gets handled immediately after we set new_mask. So, this is the trick with pselect() : Once you call a system call(enter kernel space), you can not be interrupted by anyone else. ie, you can stay in the kernel mode as long as you want; inside the implementation of the system call, we can sleep on blocking functions which can get unblocked on signals if and only if the programmer wishes to do so.

So, the above shown code works when we place it in as a system call; being in kernel mode is itself enough to prevent the race condition :-) . So, if we are using pselect(), this is how our event loop will look like :

sigset_t new_set, old_set;
int ret;

sigfillmask(&new_set);
sigprocmask(.., null, &old_set);
while(1)
{

sigprocmask(.., &new_set, null);

if(need_to_quit)

break;

ret = pselect(.., &old_set) ;

sigprocmask(.., &old_set, null);

if(ret == -1)
{

if(errno == EINTR)

continue;

}

sigprocmask(.., &old_set, null);

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值