Recent

Author Topic: Is main thread in an alertable state ?  (Read 1335 times)

engine32

  • New Member
  • *
  • Posts: 22
Is main thread in an alertable state ?
« on: September 22, 2022, 07:23:36 pm »
  Hi there,

  I want to use WSASend function to send data over network. I also want to use alertable I/O for notifications.

  I use WSASend like this:

Code: Pascal  [Select][+][-]
  1.       i32Tmp := WSASend(sHandle, @arWsaBf[0], 1, @u32SentSize, 0, @rOverlapped, @TxComplet);
  2.  

and
Code: Pascal  [Select][+][-]
  1. procedure TxComplet(u32Error, u32Len: UInt32; pOverlapped: pointer; u32Flags: Uint32);
  2. begin
  3.   frmMain.memRev.Lines.Add('WSASend Error: ' + IntToStr(u32Len));
  4. end;
  5.  

  The send action works, WSASend returns the number of bytes sent, but without procedure TxComplet being called. However, when I close the application, I see in the memo the output from the TxComplet procedure, just for a fraction of a second before the form closes.

  From my understanding, because I placed the TxComplet routine in the main thread, normally it is not in an alertable state, and becomes so briefly during the application termination (please correct me if I am wrong). I was hoping that the main thread uses SleepEx() or other similar one to pause in an alertable state.

  Do I need to use a separate thread to get this TxComplete function to fire at the right moment ? I would like to avoid multithreading.

  However, WinApi docs says here
https://learn.microsoft.com/en-us/windows/win32/fileio/alertable-i-o

Quote
alertable I/O returns the result of the I/O request only to the thread that initiated it

and I want to call WSASend from the main thread.

Thank you.

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1312
    • Lebeau Software
Re: Is main thread in an alertable state ?
« Reply #1 on: September 22, 2022, 08:04:17 pm »
I use WSASend like this:

Code: Pascal  [Select][+][-]
  1. i32Tmp := WSASend(..., @TxComplet);
  2.  

and
Code: Pascal  [Select][+][-]
  1. procedure TxComplet(u32Error, u32Len: UInt32; pOverlapped: pointer; u32Flags: Uint32);
  2. begin
  3.   ...
  4. end;
  5.  

Your callback function needs to use the stdcall calling convention.

Code: Pascal  [Select][+][-]
  1. procedure TxComplet(u32Error, u32Len: UInt32; pOverlapped: pointer; u32Flags: Uint32); stdcall;

From my understanding, because I placed the TxComplet routine in the main thread, normally it is not in an alertable state, and becomes so briefly during the application termination (please correct me if I am wrong).

You are not wrong.  That is exactly what is happening.

I was hoping that the main thread uses SleepEx() or other similar one to pause in an alertable state.

It does not.  You are responsible for putting the thread into an alertable state in your own code, ie inside the main thread's message loop.

Do I need to use a separate thread to get this TxComplete function to fire at the right moment ?

If you do not have access to put the main thread into an alertable state, then yes, you should use a worker thread instead.  Or, if you absolutely must avoid threading, then you could use a short UI timer that calls SleepEx(0) periodically, at least.

Otherwise, you can omit the callback function and instead use WSAGetOverlappedResult() in your main thread code to periodically if the send operation is finished.

I would like to avoid multithreading.

Why are you using WSASend() in the first place, instead of using send()?
« Last Edit: September 22, 2022, 08:06:34 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

engine32

  • New Member
  • *
  • Posts: 22
Re: Is main thread in an alertable state ?
« Reply #2 on: September 22, 2022, 10:34:35 pm »
  Thanks,

Quote
You are responsible for putting the thread into an alertable state in your own code, ie inside the main thread's message loop.
  Would you tell me how ?

Quote
Or, if you absolutely must avoid threading, then you could use a short UI timer that calls SleepEx(0) periodically, at least.

Otherwise, you can omit the callback function and instead use WSAGetOverlappedResult() in your main thread code to periodically if the send operation is finished.
  Currently I use send function with message notification and it works. Any timer addition I am afraid will end up with a less performant solution.

  The reason I would like to use WSASend is to improve performance. WSASend would send data directly from application buffers, while send performs a copy.

  Another reason is, Microsoft says about WSAAsyncSelect (needed for message notifications):
Quote
[The WSAAsyncSelect function is available for use in the operating systems specified in the Requirements section. It may be altered or unavailable in subsequent versions. Rather than use Select-style I/O, use Overlapped I/O and Event Objects with WinSock2.]

  This website https://www.winsocketdotnetworkprogramming.com/winsock2programming/winsock2advancedscalableapp6a.html provides a performance comparison, although the CompletionRoutine is not covered, but I suspect the performance is just lower than the completion port one.

  send and the message system does not tell me when whole data has been sent, while CompletionRoutine does.

  So now I am confused whether to use CompetionRoutine, CompletionPorts or stick with select and messages.

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1312
    • Lebeau Software
Re: Is main thread in an alertable state ?
« Reply #3 on: September 23, 2022, 08:04:52 pm »
Quote
You are responsible for putting the thread into an alertable state in your own code, ie inside the main thread's message loop.
  Would you tell me how ?

I don't know.  You would probably have to replace the main message loop with your own message loop.  This is a good reason NOT to use alertable I/O in a UI thread in the first place.

The reason I would like to use WSASend is to improve performance. WSASend would send data directly from application buffers, while send performs a copy.

That is incorrect.  A WSASend() operation copies the user's data from the WSABUF buffers into WinSock's internal buffers.  The operation is complete when the data has been copied into the internal buffers, same as with send().  The actual transmission is done in the background using WinSock's internal buffers, while your code has already been released to move on with other things in the meantime.

The only socket API that actually uses the user-provided buffers internally is Registered I/O.

Another reason is, Microsoft says about WSAAsyncSelect (needed for message notifications):
Quote
[The WSAAsyncSelect function is available for use in the operating systems specified in the Requirements section. It may be altered or unavailable in subsequent versions. Rather than use Select-style I/O, use Overlapped I/O and Event Objects with WinSock2.]

Microsoft is not in the habit of removing deprecated APIs.  Also, WSAAsyncSelect() is not the only way to get socket notifications, but it is the preferred way if you are performing your socket I/O in a UI thread, which you really shouldn't be doing in the first place.  WSAAsyncSelect() dates back to the Windows 3.x days when the whole OS was single-threaded before preemptive multithreading was introduced in Windows 95.  But WSAAsyncSelect() still works just fine in modern Windows versions.

send and the message system does not tell me when whole data has been sent, while CompletionRoutine does.

send() returns the number of bytes copied into WinSock's internal buffer.  An I/O completion routine reports the exact same thing.  The difference is that send() may return fewer bytes than requested, requiring you to call send() again to re-send the remaining data, whereas Overlapped I/O or IOCP tends to handle that internally for you, reporting completion only when all of the requested data is finished.  But that is NOT guaranteed, so you should be prepared to handle the possibility that a Completion notification reports fewer bytes than requested, requiring the remaining data to be re-sent again.
« Last Edit: September 23, 2022, 08:08:27 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

Arioch

  • Sr. Member
  • ****
  • Posts: 421
Re: Is main thread in an alertable state ?
« Reply #4 on: September 23, 2022, 08:19:18 pm »
I was hoping that the main thread uses SleepEx() or other similar one to pause in an alertable state.

It does not.  You are responsible for putting the thread into an alertable state in your own code, ie inside the main thread's message loop.

Makes me wonder why GetMessage or even PeekMessage don't do...

There is no need for GUI applicaition code to call Yield/Sleep/SleepEx, as GetMessage exactly manages idle rest for application (and did so wince Win16 times).

So on a first glance it was a soft spot for MS to process asynchronous calls, if any pending, as well.

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1312
    • Lebeau Software
Re: Is main thread in an alertable state ?
« Reply #5 on: September 23, 2022, 08:42:09 pm »
Makes me wonder why GetMessage or even PeekMessage don't do...

There is no need for GUI applicaition code to call Yield/Sleep/SleepEx, as GetMessage exactly manages idle rest for application (and did so wince Win16 times).

So on a first glance it was a soft spot for MS to process asynchronous calls, if any pending, as well.

Alertable I/O is a very specialized I/O mechanism that most apps simply never use. Only a select few functions put the calling thread into an alertable state.  (Peek|Get)Message() do not.
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

Arioch

  • Sr. Member
  • ****
  • Posts: 421
Re: Is main thread in an alertable state ?
« Reply #6 on: September 23, 2022, 09:23:24 pm »
Only a select few functions put the calling thread into an alertable state.  (Peek|Get)Message() do not.

i exactly read that part, and it puzzled me. I undersatand that this was the choice, i am puzzled what reasoning was to make it s strict.

ASerge

  • Hero Member
  • *****
  • Posts: 2222
Re: Is main thread in an alertable state ?
« Reply #7 on: September 23, 2022, 10:26:27 pm »
I would like to avoid multithreading.
and I want to call WSASend from the main thread.
You can use an Overlapped Socket I/O using an event.
Wait for the event via LCLIntf.AddEventHandler. In this case, the IOCompletion routine is nil, but the WSAOVERLAPPED structure uses the hEvent field.
The socket is configured via WSAEventSelect.
And when the event is triggered, you will get the result via WSAGetOverlappedResult.
Keep in mind that the event may be triggered when partially sending. Repeat the wait in this case.

engine32

  • New Member
  • *
  • Posts: 22
Re: Is main thread in an alertable state ?
« Reply #8 on: September 25, 2022, 12:18:42 am »
If the copy happens anyway, for my application I think it is not worth to manage buffers like Overlapped I/O or Registered I/O requires. However, I would like to switch from messages to events.

I would like to avoid multithreading.
and I want to call WSASend from the main thread.
You can use an Overlapped Socket I/O using an event.
Wait for the event via LCLIntf.AddEventHandler. In this case, the IOCompletion routine is nil, but the WSAOVERLAPPED structure uses the hEvent field.
The socket is configured via WSAEventSelect.
And when the event is triggered, you will get the result via WSAGetOverlappedResult.
Keep in mind that the event may be triggered when partially sending. Repeat the wait in this case.

For WSAEventSelect the doc says:
Quote
The WSAEventSelect sets the associated event object and records the occurrence of this event in an internal network event record. An application can use WSAWaitForMultipleEvents to wait or poll on the event object, and use WSAEnumNetworkEvents to retrieve the contents of the internal network event record and thus determine which of the nominated network events have occurred.

WSAEnumNetworkEvents returns a structure WSANETWORKEVENTS which contains the event bits and a possible error. My application is a server. In case of Windows Message, the socket associated with the client is returned in wParam. How do I get this socket handle with events ?

ASerge

  • Hero Member
  • *****
  • Posts: 2222
Re: Is main thread in an alertable state ?
« Reply #9 on: September 25, 2022, 01:02:20 pm »
How do I get this socket handle with events ?
You allocate one event for each socket. Store this pair as you like.
Inside LCLIntf, MsgWaitForMultipleObjects with the same functionality is used instead of WSAWaitForMultipleEvents.

engine32

  • New Member
  • *
  • Posts: 22
Re: Is main thread in an alertable state ?
« Reply #10 on: September 25, 2022, 04:48:34 pm »
  Thank you,

  It makes sense. Thant's why people complain about performance because multiple threads are needed to serve more than 64 events.

  With messages, the doc says:
Quote
The socket created by the accept function has the same properties as the listening socket used to accept it. Consequently, WSAAsyncSelect events set for the listening socket also apply to the accepted socket.

Quote
Inside LCLIntf, MsgWaitForMultipleObjects with the same functionality is used instead of WSAWaitForMultipleEvents.
  If MsgWaitForMultipleObjectsEx would be used, the thread could be put in an alertable mode, making possible CompletionProcs to be used.

 

TinyPortal © 2005-2018