Unix Programming - checking value of variable while blocking in a system call

This is Interesting: Free IT Magazines  
Home > Archive > Unix Programming > July 2004 > checking value of variable while blocking in a system call





You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

Author checking value of variable while blocking in a system call
Aaron Walker

2004-07-30, 5:52 pm

I am trying to write some code that writes to a FIFO (whenever there is
a reader, of course) but can't figure out how I can be able to block in
the call to open() (waiting for a reader), and at the same time check
the value of a variable (sig_atomic_t exit_flag, set to 1 when SIGINT or
SIGTERM is recieved).

I did find one way to do it, but it uses too much CPU polling (adding a
call to sleep(1) does help tremendously but just doesn't seem like The
Right Way to me):

while(!exit_flag) {
...
fd = open(file, O_WRONLY | O_NONBLOCK);
if(fd < 0) {
if(errno == ENXIO)
continue;
...
}
...
}

I thought of possibly using select() (?), but I've never used it before
and it seems complicated from reading the manual page. I checked in
UNPv2 and got the basic concept of select(), however, Mr. Stevens uses
it in a network context. From reading the manual page, though, I think
it would still end up blocking somewhere.

I'm out of ideas... can someone spare any?

Thanks
--
"And remember: Evil will always prevail, because Good is dumb." --
Spaceballs

/* Aaron Walker
* http://ka0ttic.butsugenjitemple.org/
*/
Måns Rullgård

2004-07-30, 5:52 pm

Aaron Walker <ka0ttic@butsugenjitemple.org> writes:

> I am trying to write some code that writes to a FIFO (whenever there
> is a reader, of course) but can't figure out how I can be able to
> block in the call to open() (waiting for a reader), and at the same
> time check the value of a variable (sig_atomic_t exit_flag, set to 1
> when SIGINT or SIGTERM is recieved).


Blocking system calls usually return with an errno of EINTR if a
signal arrives.

> I thought of possibly using select() (?), but I've never used it
> before and it seems complicated from reading the manual page.


Just bite the bullet, you'll have to learn how to use select() sooner
or later.

> I checked in UNPv2 and got the basic concept of select(), however,
> Mr. Stevens uses it in a network context.


select() can be used with any file descriptor.

> From reading the manual page, though, I think it would still end up
> blocking somewhere.


Of course, that's the idea with select(). However, select(), unlike
open/read/write etc., allows you to specify a timeout.

--
Måns Rullgård
mru@kth.se
Jens.Toerring@physik.fu-berlin.de

2004-07-30, 5:52 pm

Aaron Walker <ka0ttic@butsugenjitemple.org> wrote:
> I am trying to write some code that writes to a FIFO (whenever there is
> a reader, of course) but can't figure out how I can be able to block in
> the call to open() (waiting for a reader), and at the same time check
> the value of a variable (sig_atomic_t exit_flag, set to 1 when SIGINT or
> SIGTERM is recieved).


If I am understanding you correctly you have a signal handler in
the background that sets 'exit_flag' when the signal arrives. If
the signal arrives also the open() call should return and you
get a -1 return value and errno is set to EINTR. Now you can
check if the value of 'exit_flag' has been changed and thus
determine if the signal you were waiting for has arrived. So
I would guess you don't need select() or anything complicated
at all - just call open() in blocking mode and wait for it to
return. If it's because of the signal you'll know because of
the return value and errno being set to EINTR.

Regards, Jens
--
\ Jens Thoms Toerring ___ Jens.Toerring@physik.fu-berlin.de
\__________________________ http://www.toerring.de
Aaron Walker

2004-07-30, 5:52 pm

Måns Rullgård wrote:
> Aaron Walker <ka0ttic@butsugenjitemple.org> writes:
>
>
>
>


Firstly, thanks for such a quick response.

> Blocking system calls usually return with an errno of EINTR if a
> signal arrives.


That's what I thought too, however, when adding a check for EINTR, into
a normal (blocking) call to open(), nothing happens at all when the
program is thrown a SIGINT or SIGTERM.

>
>
>
>
> Just bite the bullet, you'll have to learn how to use select() sooner
> or later.


That's what I'm trying to do ;p

>
>
>
>
> select() can be used with any file descriptor.


I know that, I was just mainly confused about one thing. Wouldn't you
have to open() the descriptor before placing it in a fd_set and calling
select()? If that's the case then I have the same problem.

>
>
>
>
> Of course, that's the idea with select(). However, select(), unlike
> open/read/write etc., allows you to specify a timeout.
>


what's the best way of going about choosing a timeout? I'm clueless here...

Thanks again
--
BOFH Excuse #404: Sysadmin accidentally destroyed pager with a large hammer.

/* Aaron Walker
* http://ka0ttic.butsugenjitemple.org/
*/
Aaron Walker

2004-07-30, 5:52 pm

Jens.Toerring@physik.fu-berlin.de wrote:
> Aaron Walker <ka0ttic@butsugenjitemple.org> wrote:
>
>
>
> If I am understanding you correctly you have a signal handler in
> the background that sets 'exit_flag' when the signal arrives. If
> the signal arrives also the open() call should return and you
> get a -1 return value and errno is set to EINTR. Now you can
> check if the value of 'exit_flag' has been changed and thus
> determine if the signal you were waiting for has arrived. So
> I would guess you don't need select() or anything complicated
> at all - just call open() in blocking mode and wait for it to
> return. If it's because of the signal you'll know because of
> the return value and errno being set to EINTR.
>
> Regards, Jens



As I said in my other post a second ago, I tried this, expecting it to
work as well, but it didn't. Here's the code I had attempting to do this:

sig_atomic_t exit_flag = FALSE;

void
signal_handler(int signal)
{
exit_flag = TRUE;
}

int
main(int argc, char **argv)
{
int fd, exit_status;
struct sigaction sig;
...
sig.sa_handler = &signal_handler;
sigemptyset(&sig.sa_mask);
sig.sa_flags = 0;
...
while(!exit_flag) {
...
fd = open(file, O_WRONLY);
if(fd < 0) {
if(errno == EINTR) {
if(exit_flag)
break;
else continue;
}
perror("open");
exit_status = EXIT_FAILURE;
break;
}
...
}
...
}

Any reason why this wouldn't work?
Thanks again
--
Knocked, you weren't in. -- Opportunity

/* Aaron Walker
* http://ka0ttic.butsugenjitemple.org/
*/
Jens.Toerring@physik.fu-berlin.de

2004-07-30, 5:52 pm

Aaron Walker <ka0ttic@butsugenjitemple.org> wrote:
> As I said in my other post a second ago, I tried this, expecting it to
> work as well, but it didn't. Here's the code I had attempting to do this:


> sig_atomic_t exit_flag = FALSE;


> void
> signal_handler(int signal)
> {
> exit_flag = TRUE;
> }


> int
> main(int argc, char **argv)
> {
> int fd, exit_status;
> struct sigaction sig;
> ...
> sig.sa_handler = &signal_handler;
> sigemptyset(&sig.sa_mask);
> sig.sa_flags = 0;
> ...
> while(!exit_flag) {
> ...
> fd = open(file, O_WRONLY);
> if(fd < 0) {
> if(errno == EINTR) {
> if(exit_flag)
> break;
> else continue;
> }
> perror("open");
> exit_status = EXIT_FAILURE;
> break;
> }
> ...
> }
> ...
> }


After filling in the missing pieces (i.e. actually installing the
signal handler etc.) it works perfectly well for me - when I send
it a SIGINT or SIGTERM I can see that errno is set to EINTR and
that 'exit_flag' has been set to 1. I don't know why it isn't
working for you - can you post a complete program that doesn't
interrupts open() on a signal? Otherwise it's going to be hard to
figure out what's wrong.
Regards, Jens
--
\ Jens Thoms Toerring ___ Jens.Toerring@physik.fu-berlin.de
\__________________________ http://www.toerring.de
Aaron Walker

2004-07-30, 5:52 pm

Jens.Toerring@physik.fu-berlin.de wrote:

>
> After filling in the missing pieces (i.e. actually installing the
> signal handler etc.) it works perfectly well for me - when I send
> it a SIGINT or SIGTERM I can see that errno is set to EINTR and
> that 'exit_flag' has been set to 1. I don't know why it isn't
> working for you - can you post a complete program that doesn't
> interrupts open() on a signal? Otherwise it's going to be hard to
> figure out what's wrong.
> Regards, Jens



http://cvs.butsugenjitemple.org/vie....viewcvs-markup

once again, thanks for your help.

Cheers
Jens.Toerring@physik.fu-berlin.de

2004-07-30, 5:52 pm

Aaron Walker <ka0ttic@butsugenjitemple.org> wrote:
> Jens.Toerring@physik.fu-berlin.de wrote:
[vbcol=seagreen]
> http://cvs.butsugenjitemple.org/vie....viewcvs-markup


Sorry, but

jens@john:~> ping cvs.butsugenjitemple.org
ping: unknown host cvs.butsugenjitemple.org

Regards, Jens
--
\ Jens Thoms Toerring ___ Jens.Toerring@physik.fu-berlin.de
\__________________________ http://www.toerring.de
Aaron Walker

2004-07-30, 5:52 pm

Jens.Toerring@physik.fu-berlin.de wrote:
> Aaron Walker <ka0ttic@butsugenjitemple.org> wrote:
>
>
>
>
>
> Sorry, but
>
> jens@john:~> ping cvs.butsugenjitemple.org
> ping: unknown host cvs.butsugenjitemple.org
>
> Regards, Jens


Hmm... maybe virtual hosting isn't working as well as I thought ;)

This one *should* work:

http://butsugenjitemple.org/viewcvs....viewcvs-markup

Apologies

Aaron
Måns Rullgård

2004-07-30, 5:52 pm

Aaron Walker <ka0ttic@butsugenjitemple.org> writes:

> Jens.Toerring@physik.fu-berlin.de wrote:
>
> Hmm... maybe virtual hosting isn't working as well as I thought ;)
>
> This one *should* work:
>
> http://butsugenjitemple.org/viewcvs....viewcvs-markup


Remove these lines:

#ifdef SA_RESTART
sig.sa_flags |= SA_RESTART;
#endif

The SA_RESTART flag tells the OS that you do not want system calls to
return on signals.

--
Måns Rullgård
mru@kth.se
James Antill

2004-07-30, 5:52 pm

On Fri, 30 Jul 2004 14:58:04 +0000, Aaron Walker wrote:

> As I said in my other post a second ago, I tried this, expecting it to
> work as well, but it didn't. Here's the code I had attempting to do this:


Note that even when you fix the current bug(s), the entire approach can
fail due to race a condition between sigaction() and open().
So I'd also strongly advise that you look at using poll() (in the signal
handler you write a byte to a pipe, to convert the signal into a poll()
event).

> sig_atomic_t exit_flag = FALSE;
>
> void
> signal_handler(int signal)
> {
> exit_flag = TRUE;
> }
>
> int
> main(int argc, char **argv)
> {
> int fd, exit_status;
> struct sigaction sig;
> ...
> sig.sa_handler = &signal_handler;
> sigemptyset(&sig.sa_mask);
> sig.sa_flags = 0;


The bug might be that you don't call sigaction() here.


--
James Antill -- james@and.org
Need an efficient and powerful string library for C?
http://www.and.org/vstr/

Aaron Walker

2004-07-30, 5:52 pm

Måns Rullgård wrote:
> Aaron Walker <ka0ttic@butsugenjitemple.org> writes:
>
>
>
>
> Remove these lines:
>
> #ifdef SA_RESTART
> sig.sa_flags |= SA_RESTART;
> #endif
>
> The SA_RESTART flag tells the OS that you do not want system calls to
> return on signals.
>


I could've swore I removed that ;p
Thanks for pointing that out.

So, it works now. Now, I just have to figure out why my mail client
(thunderbird) crashes when trying to read from the FIFO... haven't used
any different mail clients yet, though, so it may just be a thunderbird bug.

Thanks again for all your help guys.
--
printk(KERN_DEBUG "%s: I'm broken.
", dev->name); linux-2.6.6/drivers/net/plip.c

/* Aaron Walker
* http://butsugenjitemple.org/~ka0ttic/
*/
Måns Rullgård

2004-07-30, 5:52 pm

Aaron Walker <ka0ttic@butsugenjitemple.org> writes:

> So, it works now. Now, I just have to figure out why my mail client
> (thunderbird) crashes when trying to read from the FIFO... haven't
> used any different mail clients yet, though, so it may just be a
> thunderbird bug.


Maybe it tries to seek in the pipe. Run strace or truss or whatever
it's called on your system and see.

--
Måns Rullgård
mru@kth.se
Barry Margolin

2004-07-30, 5:52 pm

In article <HctOc.7069$wM.5864@twister.tampabay.rr.com>,
Aaron Walker <ka0ttic@butsugenjitemple.org> wrote:

>
> I know that, I was just mainly confused about one thing. Wouldn't you
> have to open() the descriptor before placing it in a fd_set and calling
> select()? If that's the case then I have the same problem.


If you specify the O_NONBLOCK option when calling open(), the open()
call will not block when you try to open the FIFO. It will return the
descriptor immediately, and you can then put it in the fd_set in order
to wait for the other end of the pipe to be opened.

--
Barry Margolin, barmar@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
Aaron Walker

2004-07-31, 7:49 am

Måns Rullgård wrote:
> Aaron Walker <ka0ttic@butsugenjitemple.org> writes:
>
>
>
>
> Maybe it tries to seek in the pipe. Run strace or truss or whatever
> it's called on your system and see.
>


Well I ran strace on thunderbird while attempting to compose a message
(only 23MB worth of strace output for ~10s..). Turns out it is trying
to seek:

43809 open("/home/ka0ttic/.signature", O_RDONLY|O_LARGEFILE) = 31
43810 lseek(31, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek)
43811 lseek(31, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek)
43812 lseek(31, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek)
43813 lseek(31, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek)
43814 lseek(31, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek)

I guess I should check out Mozilla's bugzilla and file a bug if there
isn't one already...

It also looks like mutt won't work with fifo's either (although at least
it doesn't crash). It just says "~/.signature is not a regular file"

Makes the point of this program kinda moot if I can't use it in my two
favorite mail readers.

Anyways, thanks to everyone who helped out.

Cheers
--
I can't believe I ate the whole thing. -- Homer Simpson The Front

/* Aaron Walker
* http://butsugenjitemple.org/~ka0ttic/
*/
Måns Rullgård

2004-07-31, 5:51 pm

Aaron Walker <ka0ttic@butsugenjitemple.org> writes:

> Måns Rullgård wrote:
>
> Well I ran strace on thunderbird while attempting to compose a message
> (only 23MB worth of strace output for ~10s..).


Did you use the -e option to strace? Specifying -e trace=file will
only trace file related system calls, which can sometimes save some
lines.

> Turns out it is trying to seek:
>
> 43809 open("/home/ka0ttic/.signature", O_RDONLY|O_LARGEFILE) = 31
> 43810 lseek(31, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek)
> 43811 lseek(31, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek)
> 43812 lseek(31, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek)
> 43813 lseek(31, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek)
> 43814 lseek(31, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek)


It also seems to think it might work if it retries a few times. I
just can't understand programs that do such things.

> I guess I should check out Mozilla's bugzilla and file a bug if there
> isn't one already...
>
> It also looks like mutt won't work with fifo's either (although at
> least it doesn't crash). It just says "~/.signature is not a regular
> file"


I suppose it wouldn't be too difficult to remove that check from mutt.

> Makes the point of this program kinda moot if I can't use it in my two
> favorite mail readers.


That's why I like gnus. If it doesn't do what I want, it's usually
just a matter of adding some Lisp code to the proper hooks.

--
Måns Rullgård
mru@kth.se
Sponsored Links






Free braindumps | Software forum | Database administration forum

Copyright 2003 - 2008 webservertalk.com