Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement named threads on Windows #41736

Closed
wants to merge 2 commits into from
Closed

Implement named threads on Windows #41736

wants to merge 2 commits into from

Conversation

jsheard
Copy link
Contributor

@jsheard jsheard commented May 3, 2017

Adds support for named threads on Windows, using the very awkward convention supported by most debuggers.

example

@rust-highfive
Copy link
Collaborator

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @alexcrichton (or someone else) soon.

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

Please see the contribution instructions for more information.

@jsheard
Copy link
Contributor Author

jsheard commented May 4, 2017

Hang on, this is broken on 32-bit. I'll fix it tomorrow.

@retep998
Copy link
Member

retep998 commented May 4, 2017

The stack overflow handler is not always guaranteed to be registered, for example cdylibs that are loaded and invoked from other languages. It would perhaps be better to have a separate handler for this that is lazily registered when you set the name.

@jsheard
Copy link
Contributor Author

jsheard commented May 4, 2017

Good point @retep998, I've moved it to a separate handler.

32-bit is still broken, I think the THREADNAME_INFO struct isn't being packed correctly. The official definition declares it with #pragma pack(8) but as far as I can tell there's no equivalent modifier in Rust. Sorry if I'm missing something obvious.

@alexcrichton
Copy link
Member

Perhaps the 32-bit definition could manually fill in padding/packing/etc?

@alexcrichton alexcrichton added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label May 4, 2017
@retep998
Copy link
Member

retep998 commented May 4, 2017

I just tested the struct from the example using VC++ and as far as I can tell the #pragma pack(push,8) has no effect on the size or alignment or layout of the struct, neither on 32bit nor 64bit.

mem::size_of::<c::ULONG_PTR>()) as c::DWORD;

unsafe {
c::RaiseException(c::MS_VC_EXCEPTION, 0, size, mem::transmute(&info));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't use transmute. You can safely cast raw pointers &info as *const _ as *const _.

@jsheard
Copy link
Contributor Author

jsheard commented May 4, 2017

32-bit is now working 🎉

The struct packing was actually fine, the problem was caused by a pre-existing bug. ULONG_PTR is supposed to be a pointer-sized unsigned integer but c.rs currently defines it as an alias for c_ulonglong/u64, so set_name was getting an invalid result from size_of::<ULONG_PTR>() in 32-bit builds.

@alexcrichton
Copy link
Member

Whoa nice catch @jsheard! It looks like there's a few other locations in the codebase that define ULONG_PTR, mind updating those as well?

@alexcrichton
Copy link
Member

Awesome thanks @jsheard and thanks with the implementation! Want to squash commits and I'll r+?

@jsheard
Copy link
Contributor Author

jsheard commented May 5, 2017

I just realized there's a serious bug in my original approach. The magic 0x406D1388 exception code is not reserved for passing messages to the debugger, so if some linked non-Rust code happens to use 0x406D1388 for some other purpose the global filter would silently eat their exceptions.

With 2^32 possible exception codes this is unlikely to happen but that's no excuse 😓

I've pushed a different implementation that should be more robust. Does this look sensible?

@retep998
Copy link
Member

retep998 commented May 5, 2017

It looks like it now ignores all exceptions instead of specifically that exception code?

If only Rust exposed a way to catch SEH exceptions the way you can in Microsoft C...

@jsheard
Copy link
Contributor Author

jsheard commented May 5, 2017

It does ignore all exceptions if IGNORE_EXCEPTIONS is true, but that is only the case when we are in the process of setting a thread name. So we don't strictly need to check the code explicitly.

That said it might be more efficient to check the code anyway and early-return if it isn't MS_VC_EXCEPTION, to avoid touching the thread-local storage in the common case. Is Rust TLS expensive enough to warrant complicating the exception handler?

@alexcrichton
Copy link
Member

From the documentation vectored handlers:

The handler should not call functions that acquire synchronization objects or allocate memory, because this can cause problems. Typically, the handler will simply access the exception record and return.

Accessing TLS, however, will on Windows possibly allocate memory and acquire synchronization objects, so using TLS here may not play out so well :(

@jsheard
Copy link
Contributor Author

jsheard commented May 5, 2017

Argh, I'm out of ideas.

Perhaps we should just abandon the magic exception and focus on SetThreadDescription. It has the downside of only working on Windows 10 and literally no tools actually support it yet (not even Visual Studio), but time will solve that problem eventually.

@alexcrichton
Copy link
Member

I'd personally be ok with the original implementation, it seems like another excepting colliding with this one is exceedingly rare because it'd break anyone attempting to set the name of a thread like this, right?

@jsheard
Copy link
Contributor Author

jsheard commented May 6, 2017

@alexcrichton most programs wouldn't set a thread name like this, in C or C++ you would use Microsoft's SEH language extension to catch the exception in a scoped block like this:

__try {
    RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);  
} __except (EXCEPTION_CONTINUE_EXECUTION) {}

This is easy and safe, but impossible to express in pure Rust so we're in the unique position of trying to use program-wide VEH callbacks without causing any side effects in the rest of the program.

I'm tempted to give up and just implement SetThreadDescription, it turns out that Windows Performance Analyzer supports it now so we have something to test with. Still waiting for support in MSVC though.

@alexcrichton
Copy link
Member

If you're feeling intrepid you could actually implement that in Rust! I could help you out poking around in the compiler if you'd like. This'd basically just surface itself as a new intrinsic that's MSVC specific and also specific to the standard library. I'm not 100% sure how much work it would take, though. I believe LLVM is capable of producing the code to match the semantics of that block, so we'd just need to harness it.

@jsheard
Copy link
Contributor Author

jsheard commented May 6, 2017

I'm sure it's possible, but it would be an insane amount of work and complexity just to implement this one trivial feature. IMO there's no practical and 100% safe way to implement this via the exception.

I'll return to this when debuggers start using the new Set/GetThreadDescription APIs.

@jsheard jsheard closed this May 6, 2017
@alexcrichton
Copy link
Member

Ok that's also fine by me, thanks regardless for the PR @jsheard!

@nikhilm
Copy link

nikhilm commented Jul 18, 2018

@alexcrichton @jsheard any interest in reviving this by using SetThreadDescription now that Win10 is much more common? I could try to do this if @jsheard is busy. It will need to use GetProcAddress to check if SetThreadDescription is available.

@jsheard
Copy link
Contributor Author

jsheard commented Jul 18, 2018

Already did! It's been merged for a while now: #44374

@nikhilm
Copy link

nikhilm commented Jul 18, 2018 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants