As I mentioned several times in this blog, one of my most interesting pet-projects at work (actually, a very much work-related pet project that continues to greatly boost my productivity) is a set of tools that communicate on the PCs serial port, thus allowing control of embedded applications and cards with FPGAs or processors.

More details about this topic are here, here and here.

To communicate on the 'reading' socket from Perl's side, I needed a non-blocking read ability because I didn't want to get into threads. This turned out more difficult than I thought and at one stage I almost gave up because some ActiveState 'issue reports' state that non-blocking reads on Windows are problematic. I posted a question on PerlMonks and it got into this discussion.

Eventually, I got this to work. The solution is only two lines of (unintelligible) code:

my $nonblocking = 1;
ioctl($socket, 0x8004667e, \\$nonblocking);

ioctl is a Unix standard C function for controlling IO devices (hence its name - IO control: ioctl). Although it doesn't exist on Windows per se, it turns out that it was ported for sockets, as part of the Winsock library, which is a port of Unix sockets to Windows. Winsock has a function named ioctlsocket which is a port of ioctl for sockets.

ioctl receives a socket handle, a 'command' and a pointer. Based on the command, it either reads what the pointer points to into the device, or writes into the pointer from the device. This is why a reference must be passed as the third argument in Perl.

my $nonblocking = 1;
ioctl($socket, 0x8004667e, $nonblocking); # doesn't work
ioctl($socket, 0x8004667e, 1); # also doesn't work
ioctl($socket, 0x8004667e, \\$nonblocking); # works !

After calling this ioctl on a newly created socket, one can then freely perform non-blocking reads with sysread, which is very convenient if you are in an event loop of some kind (a Tk GUI, for instance) or just aren't sure how many characters you need to receive from the socket.


comments powered by Disqus