On Sat, Nov 06, 2010 at 12:41:11AM +0100, Matthias Bolte wrote:
2010/11/2 Daniel P. Berrange <berrange(a)redhat.com>:
> +struct virThreadArgs {
> + virThreadFunc func;
> + void *opaque;
> +};
> +
> +static unsigned int __stdcall virThreadHelper(void *data)
> +{
> + struct virThreadArgs *args = data;
> + args->func(args->opaque);
> + return 0;
> +}
> +
> +int virThreadCreate(virThreadPtr thread,
> + bool joinable ATTRIBUTE_UNUSED,
> + virThreadFunc func,
> + void *opaque)
> +{
> + struct virThreadArgs args = { func, opaque };
> + thread->thread = (HANDLE)_beginthreadex(NULL, 0, virThreadHelper, &args,
0, NULL);
> + return 0;
> +}
When you create a non-joinable thread then you won't call
virThreadJoin on it and you''ll leak the handle. Therefore, we should
use _beginthread here instead of _beginthreadex when creating a
non-joinable thread, because _endthread will close the thread's handle
when the thread's function returns.
See
http://msdn.microsoft.com/en-us/library/kdzttdcb(VS.71).aspx
> +
> +void virThreadSelf(virThreadPtr thread)
> +{
> + HANDLE handle = GetCurrentThread();
> + HANDLE process = GetCurrentProcess();
> +
> + DuplicateHandle(process, handle, process,
> + &thread->thread, 0, FALSE,
> + DUPLICATE_SAME_ACCESS);
> +}
If virThreadJoin is not called on virThreadPtr initialized by
virThreadSelf then the duplicated handle leaks.
See
http://msdn.microsoft.com/en-us/library/ms683182(VS.85).aspx
To deal with this, I'm using the same trick that GLib2
uses for libgthread, and storing the 'self' HANDLE in a
thread local that we then close when the thread exits.
> +void virThreadJoin(virThreadPtr thread)
> +{
> + WaitForSingleObject(thread->thread, INFINITE);
> + CloseHandle(thread->thread);
> +}
> +
This might create really subtle double-CloseHandle bugs when you call
it twice on the same virThreadPtr or call it accidentally on an
non-joinable thread that already exited and _endthread had close the
handle. In both cases Windows might already reused the closed handle
and the second call to CloseHandle might close something completely
unrelated.
Initializing thread->thread back to 0 should take care of that
problem.
Daniel
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org -o-
http://deltacloud.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|