
Implementation of Win32 events for Posix platforms - luu
https://github.com/neosmart/pevents
======
ComputerGuru
Thanks for posting this to HN. I originally published this some time ago when
porting a heavily-multithreaded library from Windows to Mac and Linux. It
should run on Windows/Linux/Mac/FreeBSD/etc. and it's been vetted and tested
over the years. I even came across some backtraces from Steam's Mac/Linux app
that indicated they were using my code a few years back, so there's that.

I'm a bit ashamed that I opted to write it in C++ originally. It doesn't have
much in terms of standard library dependencies (just dequeue), but in the
process of porting it to C I decided to also change how the inner
notifications system works with regards to the cleanup of allocated memory for
completed waits and now I'm stuck on a particularly nasty decision of whether
to add a mutex, use reference counting, or let memory grow until an event is
destroyed... and so the code is still C++ :)

~~~
arithma
Why ashamed with writing in C++?

~~~
ComputerGuru
Just because synchronization primitives are pretty low level so it would be
nice for it to compile as C code. I should just expose the API without name
mangling, I suppose.

(I forgot to add: the library is also free of spurious-wakeups, which I feel
is massive gotcha in pthreads.)

------
jesuslop
If you don't need wait-for-multiple-objects I had luck using c++ futures
instead of win32 events with similar semantics (calling future's promise set-
value instead of signalling the event object).

------
asveikau
At some point the Linux kernel started adding stuff that reminds me a lot of
Windows synchronization and kernel events. Like eventfd(2).

Combine that with epoll and you have something a little simpler than the code
I am reading in this library. (And like win32 events can cross a process
boundary.)

~~~
kazinator
Events are nothing more than semaphores that cannot count past 1 and clamp;
i.e. "binary semaphores". (At least the auto-reset ones.) Microsoft finally
added events that _can_ count past 1 and called them semaphores, under a
different API.

If you use this:

    
    
      HANDLE WINAPI CreateSemaphore(
        _In_opt_ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
        _In_     LONG                  lInitialCount,
        _In_     LONG                  lMaximumCount,
        _In_opt_ LPCTSTR               lpName
      );
    

and specify a maximum count of 1, you basically get the same thing as an auto-
reset event, under a different API.

Linux has had semaphores in the kernel for ages: see sem_up, sem_down.

The "event" term isn't used as a synonym for a semaphore, like in Win32.

~~~
chadaustin
"Finally"? Didn't Win95 have CreateSemaphore?

~~~
gruez
No? On the MSDN page for CreateSemaphore, it lists the minimum supported
client as Windows XP.

~~~
ComputerGuru
They cleaned up the MSDN pages (which seems a huge and sad loss of historical
data - they should include a history section like man pages), but have a look
at the Japanese page:

[https://msdn.microsoft.com/ja-
jp/library/cc429076.aspx?f=255...](https://msdn.microsoft.com/ja-
jp/library/cc429076.aspx?f=255&MSPPError=-2147217396)

It mentions it's supported on Windows 95 and NT 4.0

(On a side note, I'm completely baffled that the metadata for MSDN is not
locale-independent In their documentation generation engine/system. I would
have thought only the page text would change from one language to another.)

------
kazinator
Even includes PulseEvent: the gets() of synchronization.

~~~
ComputerGuru
Yup. But with a massive warning label and the need to explicitly define
support for PulseEvent with a compile-time definition :)

The number of bugs uncovered when switching code to not use PulseEvent() is
rather humbling!

~~~
kazinator
PulseEvent was identified as harmful more than two decades ago; there is no
reason to proliferate it. It only worked meaningfully under cooperative
multitasking in 16 bit Windows 3.x. In that OS, one task ran at a time, so it
was as if a global mutex were being held at all times.

PulseEvent resembles a condition variable broadcast which atomically gives up
the global mutex and wakes up some waiting threads. Under cooperative tasking,
if you change some shared variables and then PulseEvent, it is not possible
for some thread to see the old values of those variables, and yet miss the
wakeup, because no other thread is running. When the implicit global mutex is
gone (preemption, SMP), the function loses its reliable meaning.

PulseEvent should not have been used in 32-bit Windows 95 application coding
(preemptively multi-tasked) and thereafter. We're nearing the 21 year
anniversary of Windows 95; kids that were born when Win95 came out are
starting to pop out universities with CS degrees.

~~~
ComputerGuru
I agree with you 100% and then some. Unfortunately (and you can probably see
this by going back and looking at the commit history, <3 open source and
version control!) you have no idea the number of emails I received about this
being an "incomplete solution" and "incompatible with porting existing Win32
code" because of the lack of PulseEvent.

From the README:

    
    
        -DPULSE: Enables the PulseEvent function. PulseEvent() on Windows is 
        fundamentally broken and should not be relied upon — it will almost 
        never do what you think you're doing when you call it. pevents includes 
        this function only to make porting existing (flawed) code from WIN32 to 
        *nix platforms easier, and this function is not compiled into pevents by
        default.

