On Wed Jul 2 18:35:06 2025 +0000, Alex Henrie wrote:
It helps a lot that [Ti99Hdx](https://hexbus.com/ti99geek/Projects/ti99hdx/ti99hdx_server.html) is [open source](https://hexbus.com/ti99geek/Projects/ti99hdx/Files/ti99hdx113a_src.zip). A timer set up via SetTimer calls the ReadSerialData function in Ti99HdxCom.cpp once every 10 milliseconds, and ReadSerialData does the following:
if (!ClearCommError(hSerCom, &dwErrors, &comStat)) { return 0; } if ((dwRead = comStat.cbInQue) > 0) { if (dwRead > (unsigned int) Maxsize) dwRead = Maxsize; if (!ReadFile(hSerCom, Buffer, dwRead, &dwRead, &osSerCom)) { } else { return (int) dwRead; } } return 0;
The problem is that the program never actually checks the result of the osSerCom OVERLAPPED struct. It's requesting an asynchronous read, but then it expects data to be returned synchronously. In fact, it only calls ReadFile after checking that there is already data in the queue to be read. If no data is ever returned synchronously, dwRead is always 0, and the program doesn't do anything. Ti99Hdx never sets the serial interval timeout; it uses the default infinite timeout. Should Wine return some data synchronously even if the program did set an interval timeout? Probably. On the other hand, is there actually a program that needs that? It's weird enough that we found a program that requests asynchronous I/O that it doesn't really want. Why would a program go so far as to set a timeout if it's not actually going to check the result of the asynchronous operation?
That makes sense. It's a bit arcane, but I'm not sure I'd call it buggy. In any case set_async_direct_result is explicitly designed to allow for this. I'll probably submit a patch for that later, but I think this patch is fine for now.