Re: 'correct way' to use an I/O thread to emulate old 'blocking hook' behavior?

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance



Arkady, while you're being your usual helpful self, in this case, I don't
think you understand the original poster's problem.

The old "blocking hook" behaviour allowed 16-bit single-threaded Windows
apps to maintain some appearance that they were not locked down waiting for
network traffic.

If a recv() operation blocked, and truly blocked, without a blocking hook,
that 16-bit single thread process would be blocked, leaving nothing to
update the window, register mouse movements, repaint, etc. This looks
really bad. If you've ever seen a "hung" app, that's what it looks like.

So, instead, the "blocking hook" was created. This is, essentially, a piece
of code within the 16-bit Winsock 1.1 stack that ran through a very simple
message pump, processing Window messages and passing them back in to the
program.

This was really dangerous code, because of course it makes your Windows
program re-entrant - and a basic assumption of Windows developers is that
one message would come in at a time, and a new message would not appear
until you'd finished processing the previous message. And here was the
blocking hook, that would keep pumping the messages around, even though
you're still in the process of processing one of these messages.

It worked, and it caused only a few problems, but while it was the best
(only?) solution available for people who insisted on writing blocking apps
in 16-bit Windows, it was a really unnatural way to work, and most
developers avoided blocking sockets in true Windows apps as a result.

So, way back, the blocking hook was removed when Winsock 2.x was introduced.
[Essentially, it was removed from 32-bit Windows, because it is unnecessary
in 32-bit Windows, where you can have multiple threads.] Now, a blocking
routine really blocks - that thread is held from doing anything until the
socket operation completes.

You have three choices, in decreasing order of preference:

1. Write your app using non-blocking sockets of one form or another -
select(), WSAAsyncSelect, WSAEventSelect, Overlapped I/O, Overlapped I/O
with I/O Completion Ports - these are your options for notification of
socket operations completing.

2. Put your blocking socket operations into a separate worker thread or
process, which is designed to block, and will communicate with your display
thread in some other fashion (semaphores, mutexes, shared memory, named
pipes, etc, etc).

3. Write your own blocking hook. Note that there is scant documentation of
exactly what a blocking hook should do. It's not clear that there could be
complete documentation of what you would need, since the blocking hook
itself is essentially an admission that your code is not using the system in
a way in which it is designed to be used.

A starting point for finding out about the blocking hook would be
http://msdn.microsoft.com/library/en-us/winsock/winsock/windows_sockets_compatibility_issues_2.asp

By now, such a remnant of 16-bit Windows should be considered an archaic
anachronism, and your code should be redesigned to avoid requiring it.
Having been around the Windows network development arena long enough to know
intimately why a blocking hook was once necessary (and even at the time, it
was considered so only for really basic programs), I can tell you that a
little thought should show that this is not even as much work as writing
your own blocking hook, or splitting your program into separate threads.

One hint I would give is to start by considering WSAAsyncSelect - since this
gives you the ability to generate a Windows message from each "would block"
operation, you can split your code out as follows. Where you once had, say,
a blocking call to recv(), you will now have a call to recv(), followed by
code to see if you've received what you would have received in a blocking
fashion. If you did, run the code you would have run after the recv() in
the blocking case. If you didn't get all you wanted, you save the state of
this receive operation in some way (depends on what your program needs to
save about this operation), and return back to the message pump. When the
next receive notification comes in as a Windows message, you restore the
state, and carry on with the receive operation.

The difficulty comes only in noting which local variables you need to save
in order to "pick up" the operation once it's ready to complete, and in
saving and restoring them properly (i.e. on a 'per-socket' basis).

By comparison, writing a blocking hook, or even a separate thread to manage
your sockets, seems like an odious task.

Alun.
~~~~
--
Software Design Engineer, Internet Information Server (FTP)
This posting is provided "AS IS" with no warranties, and confers no rights.

"Arkady Frenkel" <arkadyf@xxxxxxxxxxxxxxxx> wrote in message
news:Ox8M1F8tFHA.3256@xxxxxxxxxxxxxxxxxxxxxxx
> Just use sync object(s) ( critical section in it in the same process or
> mutex e.g. in different processes ) for that
> Arkady
> "news.microsoft.com" <ryampols@xxxxxxxxxx> wrote in message
> news:OsDFTA7tFHA.1284@xxxxxxxxxxxxxxxxxxxxxxx
>>> Just Create thread ( CreateThread() ) and do there all needed work with
>>> blocked socket and main thread will be free to receive messages of the
>>> windows.
>>
>> That's fine, as long as the app can do all of its I/O asynchronously. But
>> my app has various places where it downloads little chunks of data in
>> sequence and needs to wait for downloaded data. Currently, it does this
>> via blocking I/O. Now it will have to schedule the I/O, and perform its
>> own 'wait for event' logic to simulate what the blocking I/O calls did
>> (not to mention making the GUI aware when such pseudo-blocking I/O is in
>> progress, and appropriately disabling some kinds of events till it
>> finishes).
>>
>> All of this is probably not that hard (especially in a new application),
>> but it's sufficiently different as to make it a sizeable project to
>> change over. That's why I thought I could get away with old-style
>> blocking hooks. And the documentation implied I could. And I did, and
>> it worked in win9X. It'd have been nice for the documentation to
>> correctly state that it didn't *really* work on NT-based systems, since I
>> didn't notice that it didn't work for quite a while after I coded it.
>>
>> Anyway, I guess I have my answers.
>>
>> Thanks,
>> Rob
>
>


.



Relevant Pages

  • Re: correct way to use an I/O thread to emulate old blocking hook behavior?
    ... > apps to maintain some appearance that they were not locked down waiting ... > So, instead, the "blocking hook" was created. ... > This was really dangerous code, because of course it makes your Windows ... > socket operations completing. ...
    (microsoft.public.win32.programmer.networks)
  • Re: recv blocks although socket is ready
    ... IRIX, IRIX64, Linux, OSF1, SunOS and Windows. ... Running the same app on the same hardware under Linux ... Another point which seems worth noting is, ... frequently when there is some UDP traffic on another socket. ...
    (microsoft.public.win32.programmer.networks)
  • Re: Info on Tcls channel system (specifically file events) needed
    ... >I don't know a thing about windows, so the following may be utterly ... but in unix I would simply open a domain socket and use ... I do know that there are other means than shared memory to have 2 apps ... One app is of course Tcl based, but the other need not be. ...
    (comp.lang.tcl)
  • Re: Win32 talking to *nix question
    ... If you can open a socket in delphi, you should be able to get this to work ... sub time_stamp { ... > I have a small Delphi app that runs under Windows. ...
    (borland.public.delphi.non-technical)