(open) blocks signals

Q&A's, tips, howto's
Locked
pjot
Posts: 733
Joined: Thu Feb 26, 2004 10:19 pm
Location: The Hague, The Netherlands
Contact:

(open) blocks signals

Post by pjot »

Hi,

It seems that (open) does not allow signals.

Code: Select all

#!/usr/bin/newlisp

(constant 'SIGUSR1 10)

(signal SIGUSR1 exit)

# Create FIFO
(exec "mkfifo myfifo")

# Open FIFO file
(open "myfifo" "read")

(exit)
Now, when I pass 'kill -s SIGUSR1 1874' from another terminal, where 1874 is the PID of the newLisp program, nothing happens, while I want the program to exit.

How is this possible? When newLisp is running a command like (println), and a SIGUSR1 occurs, the program is exited, as expected. But not with the (open) statement. I assume it has to do with the pipe-file, which is opened in a blocking way? Would it still be reasonable to expect that a signal can exit the program in this situation?

Peter

pjot
Posts: 733
Joined: Thu Feb 26, 2004 10:19 pm
Location: The Hague, The Netherlands
Contact:

Post by pjot »

All right I discovered the non-blocking mode. The manual reads:
As an additional str-option, "non-block" or "n" can be specified after the "read" or "write" option. Only available on UNIX systems, non-blocking mode can be useful when opening named pipes but is not required to perform I/O on named pipes.
But still it does block in case of "write" access.

Code: Select all

#!/usr/bin/newlisp

(constant 'SIGUSR1 10)

(signal SIGUSR1 exit)

# Create FIFO
(exec "mkfifo myfifo")

# Open FIFO file
(open "myfifo" "write" "n")

(exit)
When opened in "read" mode, the program continues, but in "write"-mode this seems not to be the case; it still blocks. And any occuring signal is ignored (except for KILL, of course).

Peter

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

The non-blocking opening mode is handled and described differently on different UNIX platforms. Internally newLISP adds the O_NONBLOCK flag to the open() call.

newLISP offers whatever the underlying UNix platform delivers for this mode. The results differ on BSD, Linux and Solaris.

On BSD non-blocking seems to refer only to the opening process itself. On Linux it also refers to other subsequent read/write operations but only on fifos. On Solaris the option seems to influence reading/writing to any device opene with open. In a multi user situation things also change if there is concurrent acces from other users.


Lutz

pjot
Posts: 733
Joined: Thu Feb 26, 2004 10:19 pm
Location: The Hague, The Netherlands
Contact:

Post by pjot »

Hi Lutz,

Thanks, I also checked the sourcecode of newLisp and to me it seems OK.

Still, would there be a workaround for this situation?

To define my problem more precisely: I want to communicate with another process by using a FIFO pipefile, and I want to prevent that newLisp keeps waiting forever when the other side has not sent data over the pipe, or has not opened the pipe at all (which seems to be the cause of all this trouble).

The (peek) function cannot be used because it already needs an 'opened' handle to peek from.

With BASH and Kornshell it is the easiest thing to overcome: I can write to a FIFO pipefile with a plain 'echo' without any blocking issues.

In newLisp it seems possible to read and write to a FIFO pipefile, but solely by using the 'open/close' statements, which may block when the other side of the pipefile has problems. How can I solve this issue in a lispy way? Or should I spawn an 'echo' in a subshell (hope not)?

Peter

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

This is how it works for me after doing a:

Code: Select all

mkfifo myfifo
In the first process:

Code: Select all

> (open "myfifo" "read" "nonblock")
3
> (read-line 3)
nil
> (read-line 3)
"hello"
> (read-line 3)
nil
> (read-line 3)
"hello"
> (read-line 3)
The reading process does not block, but returns 'nil' when nothing ready in the FIFO.

The second process doesn't block on writing either:

Code: Select all

> (open "myfifo" "write")
3
> (write-line "hello" 3)
"hello"
> (write-line "hello" 3)
"hello"
> 
All writes are non-blocking and can be read asynchronously by the reading process. When the pipe is empty it returns 'nil'. You could measure the time or count the nil's received to timeout.

Lutz

ps: This is on Mac OS X (a BSD flavor)

pjot
Posts: 733
Joined: Thu Feb 26, 2004 10:19 pm
Location: The Hague, The Netherlands
Contact:

Post by pjot »

Well, unfortunately it is not the same on Linux.
peter[~]$ mkfifo myfifo
peter[~]$ newlisp
newLISP v.9.0.16 on Linux, execute 'newlisp -h' for more info.

> (open "myfifo" "write")
And now newLisp hangs - forever. So I do not even have the possibility to perform a (write-line). The same thing happens when opening the FIFO pipefile with the "n"-flag.

Opening for "read" works good, though.

The situation you describe is what I would expect, also in Linux. Unfortunately this issue seems to lead to sourcecode which is not Unix-BSD portable.

Peter

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

I will not be able to look into this in the near future, at the moment my only OS access is to OX X, FreeBSD and Solaris. I can boot UBUNTU from a life CD but that is not a situation suited for development.

Perhaps you can help? Should be something very simple. The only thing happening here is an open() with different flags set. The functions involved are openFile() and p_write().

Lutz

pjot
Posts: 733
Joined: Thu Feb 26, 2004 10:19 pm
Location: The Hague, The Netherlands
Contact:

Post by pjot »

Lutz, I think I found the error. This is in 'nl-filesys.c' of newLisp 9.0.16:

Code: Select all

 607 if(*accessMode == 'r')
 608         return(open(fileName, O_RDONLY | O_BINARY | blocking, 0));
 609 
 610 else if(*accessMode == 'w')
 611 #ifdef WINCC
 612     return(open( fileName, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE) );
 613 #else
 614     return(open(fileName,O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
 615         S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH | blocking)); <----------- !!! FILEMODE here
 616 /*        S_IRWXU | S_IRWXG | S_IRWXO | blocking));  rwxrwxrwx */
 617 #endif
Now look where 'blocking' is mentioned. You can see it at line 615, but this is the wrong position. Because here it specifies a filemode.

It should be part of the opening flags. I have changed the code as follows:

Code: Select all

 607 if(*accessMode == 'r')
 608         return(open(fileName, O_RDONLY | O_BINARY | blocking, 0));
 609 
 610 else if(*accessMode == 'w')
 611 #ifdef WINCC
 612     return(open( fileName, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE) );
 613 #else
 614     return(open(fileName, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | blocking,   <------------
 615         S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH)); /* rw-rw-rw */
 616 /*        S_IRWXU | S_IRWXG | S_IRWXO | blocking));  rwxrwxrwx */
 617 #endif
Now it works, blocking and non-blocking,

Why the previous code worked on BSD is a riddle to me. But then again, I have stopped to grasp everything in this world. ;-)

Peter

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

Ooops, now I see it, thanks very much Peter

Lutz

Locked