
Andreas Voellmy
Another way to fix usb would be to re-register the callback after a previously registered callback is fired. Of course it is cheaper not to have to re-register, but re-registration in the latest IO manager should be fairly cheap, so this may not be a performance problem for usb. Would this work for you?
You could also use a CPP directive to only do this for GHC 7.8 and up.
This is a possibility that I had considered. It would require that some code be reworked however. I'm leaning towards just using our non-event-manager-driven fallback path on GHC 7.8 for now until the event manager semantics can be worked out.
If we want to allow usb to work unchanged, then we will have to revert to the non-ONE_SHOT behavior of registerFd and add some things to the API to allow GHC.Thread to register with ONE_SHOT behavior. Reverting could break clients of this semi-public API who have adapted to the 7.8 behavior. There probably aren't of these clients other than GHC.Thread, so this may not be a big issue.
I don't think we need to revert the changes just for usb as we have the fallback path that will work for now. I do think it might be good to explore other points in the design space, however.
To do per-FD setting of ONE_SHOT or not, we actually need to have per-subscription settings, since there can be multiple invocations to register callbacks for a single file descriptor (e.g. from two different threads) and they might want different settings.
Agreed.
If all the clients want ONE_SHOT we use ONE_SHOT registration, if all want persistent registrations we don't use ONE_SHOT. If it is mixed, then the manager has to choose one or the other and simulate the required behavior for the other registrations (e.g. choose persistent and automatically unregister for ONE_SHOT registrations). We could either always make the same choice (e.g. if there is a mix, use persistent), or we could have per-FD setting that is configurable by clients.
I would think we would actually want the desired one-shottedness to be a property of the registration. We would have, -- | Will this registration be valid until unregistration ('ManyShot') -- or only for a single event ('OneShot')? data Lifetime = OneShot | ManyShot registerFd :: EventManager -> Fd -> Event -> Lifetime -> IO FdKey The event manager would then have to choose either ONE_SHOT or not in the case of heterogenous registrations and emulate the other set, as you said. This seems like a nice interface as it allows the user to specify the semantics that they want (instead of working around whatever the manager happens to provide) and gives the the event manager enough knowledge and freedom to do what it can to efficiently implement what is needed. Cheers, - Ben