-
Notifications
You must be signed in to change notification settings - Fork 0
WaitHandles
This page discusses the evolution of the FreeRDP wait handle API.
In the non-Windows world, file descriptors + select/poll/epoll are the norm. However, file descriptors are not usable on Windows in the way which we would need them, making them unsuitable as the primary form of wait handle. In the Windows world, waitable object HANDLEs are passed to WaitForSingleObject/WaitForMultipleObjects. This is the strategy used and preferred in FreeRDP/WinPR.
Historically, the API provided by FreeRDP was the following:
BOOL freerdp_get_fds(freerdp* instance, void** rfds, int* rcount, void** wfds, int* wcount);
BOOL freerdp_check_fds(freerdp* instance);
This API has the following limitations:
- It was designed with file descriptors in mind
- There is no way to prevent writing beyond the end of the lists
- There is no way to know how many handles are available beforehand
- HANDLEs can be passed as void*, but this requires platform-specific usage
- The counts is really an index in the file descriptor set, not a count
Here is a list of requirements for a proper wait handle API:
- Usage should be the same on all platforms for the regular cases
- The application must be free to obtain the handles to do the waiting
- Wrapping of file descriptors in event handles must be made possible
- Extraction of internal file descriptors from event handles is possible
- The API must support providing a list of wait handles, not just one handle
- Repeating code which waits on handles across applications is acceptable
DWORD freerdp_get_event_handles(rdpContext* context, HANDLE* events);
BOOL freerdp_check_event_handles(rdpContext* context);
freerdp_get_event_handles returns the number of event handles. To query the number of event handles without writing them to an event handle array, set HANDLE* events to NULL. As the function names imply, the handles returned are event handles, or at least handles that can be used like event handles.
To wrap a file descriptor in an event handle, CreateFileDescriptorEvent() can be used. To extract a file descriptor from an event handle, GetEventWaitObject() can be used.
In the vast majority of cases, the strategy will be to obtain event handles, wait on them with WaitForMultipleObjects, and then check either individual handles or group of handles with WaitForSingleObject/WaitForMultipleObjects to identify which ones are set and then call the associated function.
The double checking is necessary because there is no way to ensure that a single event out of the list was set when WaitForMultipleObjects returned. The status code only tells you the lowest index out of the indices of set events. If you rely on the status code, you can possibly lose events if more than one event are set at the same time.