[PD] preventing comport freezes

Martin Peach martin.peach at sympatico.ca
Fri May 29 00:47:53 CEST 2009


Hans-Christoph Steiner wrote:
> 
> On May 14, 2009, at 6:56 PM, Martin Peach wrote:
> 
>> Hans-Christoph Steiner wrote:
>>> On May 9, 2009, at 2:43 PM, Martin Peach wrote:
>>>> Roman Haefeli wrote:
>>>>> thanks for the info.
>>>>> On Fri, 2009-05-08 at 19:27 +0000, martin.peach at sympatico.ca wrote:
>>>>>>> just out of curiosity: if there is a solution, that works well for
>>>>>>> [tcpserver], couldn't it be applied also to [comport]?
>>>>>>>
>>>>>> Maybe. But I think you should be able to use [comport] with no
>>>>>> hardware handshaking enabled and send data even if no cable is
>>>>>> attached. Sometimes the absence of one of the two input handshake
>>>>>> signals prevents the serial hardware from sending. Also if an error
>>>>>> occurred in the reception of serial data it may not be handled
>>>>>> properly in [comport]. So I'm not sure what is causing this 
>>>>>> particular
>>>>>> crash, since HC said that it happened when the remote device was
>>>>>> disconnected but gave no further detail.
>>>>> iirc, on linux at least, [comport] makes pd hang, _whenever_ the other
>>>>> end disappears. i.e.:
>>>>> - pulling out the usb-cable, while the arduino is connected
>>>>> - turning off an rfcomm device
>>>>
>>>>
>>>> This looks like something related to the usb interface. I think 
>>>> pulling out an RS-232 cable has no effect, as the serial driver can 
>>>> only be closed by [comport]. With a usb adapter the usb driver can 
>>>> close the port.
>>>> I suspect that the comport_tick routine, which is called 
>>>> periodically to check for received characters, tries to access the 
>>>> serial port after the usb driver has closed it.
>>>> The non-Windows code in comport_tick looks like this:
>>>>
>>>> unsigned char   serial_byte;
>>>> fd_set          com_rfds;
>>>> int             count = 0;
>>>>
>>>> FD_ZERO(&com_rfds);
>>>> FD_SET(fd,&com_rfds);
>>>>
>>>> while((err=select(fd+1,&com_rfds,NULL,NULL,&null_tv)) > 0)
>>>> {
>>>>   err = read(fd,(char *) &serial_byte,1);
>>>>   outlet_float(x->x_data_outlet, (t_float) serial_byte);
>>>>   ++count;
>>>> }
>>>>
>>>> As you can see the select call only checks for the presence of 
>>>> received characters with com_rfds, and doesn't check the write or 
>>>> exception status. I suppose the select call should also check the 
>>>> exception fd_set, as the usb driver has no other way of informing 
>>>> [comport] that it has closed the port, it should have flagged it there.
>>>> (Although if the fd itself is no longer valid I don't know what to 
>>>> do...using non-existent file descriptors is a good way to crash Pd)
>>>>
>>>> ATM I only have 'legacy' RS-232 ports on my hardware so I can't test 
>>>> it, but I can change the code.
>>>>
>>>> Martin
>>> Ok, quick test shows a couple things:
>>> - just using [comport 1 115200] and then yanking the USB out causes 
>>> the crash, so no data needs to be sent to cause this.  This is with a 
>>> standard Arduino USB.
>>
>> So the crash most likely occurs when comport_tick is called by the timer.
>>
>>> - in the select() that you highlight, it is just testing before 
>>> reading, so I am guessing it would not be so useful to do a write 
>>> test if it is only going to read().
>>
>> The write test is not needed, but I was thinking that the third 
>> possible test, the exception test, might give useful info, unless the 
>> file descriptor has already become invalid, in which case I don't know 
>> what to do about it, since using a dead file descriptor is usually 
>> lethal and probably is what is causing the crash.
>> How does [hid] react to unplugging of the device?
> 
> In [hid] I don't remember doing anything special, I never even used 
> select(). I am guessing that serial ports behave differently that USB 
> HID.  Serial was designed to be permanently attached, USB was designed 
> to be hot-pluggable.   Here's the read() for example:
> 
>     while( read (x->x_fd, &(hid_input_event), sizeof(struct 
> input_event)) > -1 )
> 
> I open it using read-only and non-blocking, maybe that has something to 
> do with it?
> 
>     x->x_fd = open(block_device, O_RDONLY | O_NONBLOCK);
> 
> I just tried a test with just a USB serial adapter, it didn't actually 
> crash, it just stopped responding and pegged the CPU.
> 

Well I got hold of an Arduino Diecimila and played around with the 
[comport] code on an up-to-date Debian box but no luck. I tried select() 
to see if the port is still writeable, as well as to see if any 
exceptions occurred, but no. Also I tried trapping the SIGHUP that's 
supposed to be sent but I didn't get any.
There seems to be an issue with the FTDI driver for linux, as mentioned 
in some bug reports and patches (Arduino is using an FTDI USB to serial 
converter). It seems that it doesn't close properly when it's 
hot-unplugged; even though /var/log/messages gets written to when the 
close happens, no SIGHUP is sent.
So we probably have to wait for the patches to trickle down into the 
next kernel.

Martin







More information about the Pd-list mailing list