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
Eventtap randomly stops intercepting events #1103
Comments
I have similar problem. My theory is that eventaps are collected by GC. |
As a general recommendation, I would try to avoid having anything in your init.lua be a (If you've seen any official docs/guides that use locals, please shout at me, and I'll fix them!) While we're on the subject, @asmagill and @Habbie and I have had some on/off discussions about whether we should implicitly retain references to all of our created objects, so they don't get GC'd, so we may be able to avoid this horrible discovery in future, but it needs a good deal of thought since we'd then be potentially piling up objects for days/weeks/months. |
For example: http://www.hammerspoon.org/go/ section "Fancy configuration reloading" If you put The same for "Reacting to application events" and I think every other watcher. |
Opps! I didn't realise this. I wrongly interpreted "A quick aside about variable lifecycles" in Getting Started with Hammerspoon to say as long as you "capture them in a variable" in So basically, what you're saying @cmsj is that the ONLY time you should use |
Thanks, Denis! |
collection This was causing eventtap bindings to fail after a random time because they were being garbage collected. Hammerspoon/hammerspoon#1103 (comment)
@cmsj & @asmagill - Quick question regarding the whole global vs local discussion. If a module is made global within |
As a general rule of thumb, all watchers and timers should be captured in a global variable. An exception to this requirement is when a local variable is captured within the scope of a function which is captured in a global variable or the Lua registry. If the last line doesn't make sense, see below, or take the simpler approach of just making sure to capture them in global variables. To keep from name collisions, I separate most of my stuff into separate files, then create a table that all of the watchers, etc. get added to for that file, then return that table at the end of the file. When I invoke the file with Optional Explanation of Exception listed above: Take for example the following code (copy and paste both lines into the console as one, if you want to try it yourself): local a = 0
increment = function() a = a + 1 ; return a end In this case, > a, increment()
nil 1
> a, increment()
nil 2
> a, increment()
nil 3
> a, increment()
nil 4
etc. Similarly when you register a callback function for most of our watchers, etc. the function itself has a reference stored in a special table referred to as the LUA_REGISTRY. The registry is effectively a "global" table available to all C-API functions/methods (or with So s = false -- global
local a = 0
local t
t = hs.timer.doEvery(1, function() if not s then a = a + 1 ; print(a) else t:stop() end end) Gives the following output: 1
2
3
> collectgarbage() -- if we hadn't captured `t` in the callback function, this would stop the timer
0
4
5
> s, a, t
false nil nil
6
7
> s = true -- this finally stops the timer, since `s` was the only global |
Legend, thanks so much @asmagill ! This needs to go in the FAQ or Getting Started with Hammerspoon - very helpful! |
It's a topic that I've been planning to add to the wiki documents that I hope to work on this month. For completeness (when I refer back to this for the wiki doc), the final example really should be more like this: s = false -- global
local a = 0
local t
t = hs.timer.doEvery(1, function()
if not s then
a = a + 1
print(a)
else
t:stop()
t = nil -- without this, the timer can never actually get collected, even though we've stopped it
end
end) For a timer, the object is relatively small, so it would take a lot of them to actually cause a noticeable memory leak, but some of the other objects behind the modules are notably larger |
refs: Hammerspoon/hammerspoon#1103 Garbage Collection disables eventtap
From #689 :
@asmagill
I'm currently playing with eventtap (Hammerspoon 0.9.49 and 0.9.50, MacOS 10.12.1, MBP Retina, 13-inch, Early 2015) and It seems to be working fine for me, but It randomly stops to intercept events. It might be related to the issue cited above.
Currently my config looks this way: https://gist.github.com/eoranged/b05481d2a2646a84a15da88a53304d92
It usually takes ~30-90 minutes to happen, but sometimes everything works fine for couple days. I don't see any pattern here. Callbacks are not executed until I reload config.
The text was updated successfully, but these errors were encountered: