Re: How to kill a kqueue camper thread? Was: close() hangs … in 10.5 only
Re: How to kill a kqueue camper thread? Was: close() hangs … in 10.5 only
- Subject: Re: How to kill a kqueue camper thread? Was: close() hangs … in 10.5 only
- From: Terry Lambert <email@hidden>
- Date: Fri, 20 Aug 2010 11:16:39 -0700
On Aug 20, 2010, at 4:35 AM, Jerry Krinock wrote:
> On 2010 Aug 20, at 01:28, Terry Lambert wrote:
>>> Why not have a timeout on the kevent…
>>
>> This is _a_ way, but your timeout would need to be tight to ensure that it was more or less responsive…
>
> Actually I could do that, since this is just to clean up resources; no hurry. But then there's that "elegance" thing. "Polling", anyone? Seems like it defeats the purpose of kqueue.
>
>> Alternately, the NSThread in 10.5.x is based on a pthread, so you could do:
>> volatile pthread_t kqueue_thread;
>> // called within the thread before looping
>> kqueue_thread = pthread_self();
>
> Yes, this is one of your previous suggestions, to have the secondary thread feed back its thread ID. I kind of like your first suggestion better, to get the thread ID from pthread_create(). Warning: I've never done this – just reading docs. But I'll get it one way or the other.
The suggestion was made on the basis of incomplete information, which is why I gave a shotgun answer to cover all possible bases, given your observed behaviour. I wouldn't suggest throwing out NSThread and object encapsulation over this.
>> There's no guarantee that future versions of NSThread will be based on the same primitives, but you can be pretty sure that there's not going to be a change in that regard in a 10.5.x, so as long as you check your OS version at runtime …
>
> Terry, I believe you're suggesting that I execute my current code for 10.6+, which relies on the fact that when I EV_DELETE a kqueue from the main thread, kevent() on the secondary thread returns -1 with errno=EINTR immediately.
Yes.
> Certainly this is a very welcome new feature! But is it by design? Will it work in 10.7+? Where is it documented? If you're sure it's in there for keeps I shall happily file feedback to Apple on the documentation.
I can't make forward looking statements about things like that. It works that way by design in 10.6.x. You could always ask for a documentation change to try and tie our hands in future versions.
I tend to like to keep documented interface contracts to a minimum in man pages I work on, though, so as to not preclude doing something clever in the future; being with the IEEE, you can probably appreciate that, since POSIX says nothing about close(2) triggering cancellation of outstanding I/O operations vs. blocking until those operations complete. Writing code that depends on cancellation is therefore non-POSIX code which depends on implementation-defined behaviour.
-
A.M. has suggested a "quit pipe". I would recommend against it.
This is where you add a socketpair(2) or a pipe(2) system call to get a connected descriptor pair, and then add it as another event source which is monitored by your camping thread. When you want to quit, you write a byte down the pipe or socket, the kevent for the pipe fires in the worker thread, it wakes up, and quits because of the fact of the message, or its contents. I may even have suggested this to A.M. as a solution to a previous problem. This method has been used with select, and to implement a "select" via pipes and processes on systems without select (e.g. pre-BSD4.1g UNIX systems, like pre-modern Altos Xenix, Sun 3, and so on, systems).
The negative thing about that approach is that what we are trying to do here is work around a 10.5 issue that doesn't exist in 10.6, and it's moderately invasive and error prone. Here are the reasons I'd personally prefer to use a signal:
(1) You can set up the signal sender after the signal thread because of the asynchronous initialization of the global; otherwise, it's all setup work.
(2) The approach consumes two file descriptors; your default per-process limit is 256.
(3) A close of the fd on the sender end could happen as a result of a framework; a global integer (pthread_t) is less likely to be stomped.
(4) A close of the fd on the sender will trigger an EOF condition, but not a read-ready condition, if you haven't asked for that notification, so it's somewhat error prone.
(5) This is throw-away code, and the approach is less invasive of your future versions if you use a signal.
(6) The signal can be targetted to a specific thread
(7) There's no danger of accidental or intentional interception of a thread-directed signal (well, without setting up a mach special port handler for the thread, anyway).
I think the benefits of async initialization, no additional fd worries, and the mechanism being orthogonal to interfaces you are probably already using is enough of an argument to sell the signal approach.
I'd also caution *against* adding the signal itself as a kevent() in the receiver as was suggested, since doing that's not a thread-specific thing at that point: kqueues, being based on file descriptors, are not per-thread. Other kevent() calls could see it -- for example the GCD dispatch thread. That could be bad.
-- Terry _______________________________________________
Do not post admin requests to the list. They will be ignored.
Darwin-kernel mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden