(open) blocks signals

Started by pjot, January 15, 2007, 04:01:27 AM

Previous topic - Next topic

pjot

Hi,



It seems that (open) does not allow signals.



#!/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

#1
All right I discovered the non-blocking mode. The manual reads:


Quote
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.



#!/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

#2
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

#3
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

#4
This is how it works for me after doing a:
mkfifo myfifo

In the first process:


> (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:


> (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

#5
Well, unfortunately it is not the same on Linux.


Quote
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

#6
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

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



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:



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

#8
Ooops, now I see it, thanks very much Peter



Lutz