|
From: Greg P. <gp...@ap...> - 2009-12-09 22:36:44
|
On Dec 9, 2009, at 1:50 PM, Konstantin Serebryany wrote: > On Wed, Dec 9, 2009 at 11:42 PM, Greg Parker <gp...@ap...> wrote: >> On Dec 9, 2009, at 9:13 AM, Alexander Potapenko wrote: >>> >>> drd: drd_thread.c:584 (vgDrd_thread_set_vg_running_tid): Assertion >>> vg_tid != VG_INVALID_THREADID' failed. >>> ==68403== at 0xF009DCBD: ??? >>> ==68403== by 0xF009DF71: ??? >> >> First guess: either Valgrind or those tools aren't correctly handling the thread-creation mechanisms used by NSOperationQueue. Work queues don't go through the normal thread entry points. > > You mean that NSOperationQueue can create a thread w/o calling pthread_create()? That's right. (There's also pthread_create_suspended_np(), but I don't know of anyone who uses that.) > Than yes, the tools don't know anything about that. > Could you point to any piece of documentation and/or source code which explains how threads are created by NSOperationQueue? Valgrind works at the kernel interface. At this level, pthreads mostly don't exist; the kernel deals in Mach threads, and pthreads are built on top by Libc. In particular, there is no pthread_create() system call. Workqueue threads are another kernel construct used to support NSOperationQueue and Grand Central Dispatch. Most of the time a workqueue thread does get a pthread built atop it, just like most Mach threads are wrapped in a pthread. But the construction process is different, and does not call Libc's pthread_create(). Workqueue threads are created at the kernel's whim. They simply appear in the process without an explicit user-space request. Each workqueue thread starts its execution de novo in a function provided by Libc, which builds the pthread if necessary and executes a work item. During process startup, Libc calls the bsdthread_register() syscall, which among other things tells the kernel the entry point for new workqueue threads (_pthread_wqthread()). Valgrind traps bsdthread_register() and substitutes its own function wqthread_hijack_asm(). When the kernel starts a workqueue thread in a Valgrind process, it starts in wqthread_hijack_asm() on the real CPU, which in turn bootstraps the thread into Valgrind's simulator and calls Libc's entry point. Valgrind's pthread-tracing system would need to do its work inside wqthread_hijack(). I think workqueue threads call the ordinary pthread_exit() on their way out, so you might not need extra handling there. I don't know of any documentation for any of this; like the rest of the kernel-libc interface, it's private and subject to change at any time. Everything I know I learned from reading xnu and Libc source. -- Greg Parker gp...@ap... Runtime Wrangler |