Skip to content
This repository has been archived by the owner on Jan 22, 2022. It is now read-only.

Correct threading model used by wmi calls #13

Closed
wants to merge 2 commits into from

Conversation

stevenh
Copy link
Contributor

@stevenh stevenh commented Jun 8, 2016

WbemScripting is apartment threaded according to its registry entries so switch multi-threaded OLE to apartment threaded enabling the global lock to be removed.

Correct missing CoUninitialize call when CoInitializeEx returns S_FALSE as documented here:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms695279(v=vs.85).aspx

Also:

  • Cleanup OleError checking in Query.
  • Handle nil return from CreateObject by returning ErrNilCreateObject before it causes a panic. This has been seen in rare cases in production when built under go v1.6.

stevenh added 2 commits May 26, 2016 11:51
WbemScripting is apartment threaded according to its registry entries
so switch multi-threaded OLE to apartment threaded enabling the global
lock to be removed.

Correct missing CoUninitialize call when CoInitializeEx returns S_FALSE
as documented here:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms695279(v=vs.85).aspx

Also:
* Cleanup OleError checking in Query.
* Handle nil return from CreateObject by returning ErrNilCreateObject
  before it causes a panic. This has been seen in rare cases in production
  when built under go v1.6.
Correct threading model used by wmi calls
@ahall
Copy link

ahall commented Jul 26, 2016

I am using this in production now along with the Enum changes. Who can we get to merge these pull requests? Pretty messy having to apply them manually. Is @mjibson no longer maintaining this? :).

@maddyblue
Copy link
Contributor

I'm not maintaining this anymore. @gbrayut may be, or may know who should look at these PRs.

@gbrayut
Copy link
Contributor

gbrayut commented Jul 26, 2016

I staged these at https://github.com/StackExchange/wmi/tree/next and will do some testing before merging to master

@gbrayut
Copy link
Contributor

gbrayut commented Jul 26, 2016

Holding off on merging... appears to be a memory leak. See Unity-Technologies#8 (comment)

@gbrayut
Copy link
Contributor

gbrayut commented Jul 27, 2016

Merged in #16 but we kept the lock and ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED) as ole.CoInitializeEx(0, ole.COINIT_APARTMENTTHREADED) caused a memory leak

@gbrayut gbrayut closed this Jul 27, 2016
@gbrayut
Copy link
Contributor

gbrayut commented Jul 28, 2016

Hmm... still seeing a memory leak, although much slower than the apartment threaded one:

image

I am going to try reverting the ole.CoUninitialize() logic back into an else block. We may not be initializing things correctly (this says it is only needed once per thread and SHOULD have matching calls to CoUninitialize) but I'm not sure how to do that when the method is called by many go routines.

We didn't see any issues with the old logic, and the nil check would remain to fix the potential panic reported on the multiplay repo.

@stevenh
Copy link
Contributor Author

stevenh commented Jul 28, 2016

Hmm that does sound very broken upstream as the MS docs do explicitly state, as you know:

To close the COM library gracefully on a thread, each successful call to CoInitialize or CoInitializeEx, including any call that returns S_FALSE, must be balanced by a corresponding call to CoUninitialize.

With regards to balancing the calls that's not something you need to worry about as its uninitialized before the method returns by the defer so the calls are explicitly balanced and as the thread is locked for the duration that thread cant be used by any other executing goroutine for the duration.

Do you have a small re-production case you could share?

@gbrayut
Copy link
Contributor

gbrayut commented Jul 28, 2016

The code base is https://github.com/bosun-monitor/bosun/tree/master/cmd/scollector and https://github.com/bosun-monitor/bosun/blob/master/cmd/scollector/collectors/cpu_windows.go#L16 is an example of a collector that gets run every 15s. There are other collectors also creating WMI queries using 90-100 total go routines.

I suspect https://github.com/StackExchange/wmi/blob/master/wmi.go#L12 would have the same issue if it is run in a go benchmark, but I'm on day two of what I though would be a quick merge so I don't have time to test that.

So far testing with the old CoUninitialize code looks better, but I'll need to let it run for a few more hours to confirm:

image

@gbrayut
Copy link
Contributor

gbrayut commented Jul 28, 2016

I think I found it. It wasn't this PR, it was the Use _NewEnum one which was missing a call to Release(). #14 (comment)

We will leave the new ole.CoUninitialize() code in, as testing that by itself did not cause any issues.

@stevenh
Copy link
Contributor Author

stevenh commented Jul 28, 2016

Cool thanks for the update @gbrayut that would explain why we never saw an issue in our production environment either.

If adding that missing Release() does indeed fix it adding back in the switch to apartment threading would also be good to see :)

@gbrayut
Copy link
Contributor

gbrayut commented Jul 29, 2016

I let it run overnight with apartment threading and it looks slightly higher but no leak. I'll merge that in to master shortly

image

Thanks!

gbrayut added a commit that referenced this pull request Jul 29, 2016
This reverts commit d4ae5b4.
leak was in another PR.
See notes at #13 (comment)

# Conflicts:
#	wmi.go
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants