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

[python] add xbmc.abortEvent #5217

Merged
merged 2 commits into from Aug 31, 2014
Merged

Conversation

tamland
Copy link
Member

@tamland tamland commented Aug 14, 2014

I intend this as a simple replacement of the boolean property. It allows add-ons to use xbmc.abortEvent.isSet() instead, and most importantly xbmc.abortEvent.wait()instead of periodically checking.

Missing:
- Documentation: surely this is currently done by magic, so I'm hoping at least the abortEvent attribute should be documented.

  • Deprecation of abortRequested: need elaborate hacks in initialization script to do this.

@MartijnKaijser
Copy link
Member

  1. Leave abortRequested for time being as a lot of scripts use this. We should deprecate it in perhaps two releases so they have enough time to transfer.

@jimfcarroll for code review and idea for documentation. Maybe there's a better way of doing this so also JSON-RPC can benefit from it like the other using the monitor class. (https://github.com/xbmc/xbmc/blob/master/xbmc/interfaces/legacy/Monitor.h) @Montellese ? I'm sure that JSON-RPC users would welcome knowing if device will be shutdown.

Edit: like the other python addition, at the same time the python API should be bumped.

@MilhouseVH
Copy link
Contributor

Good to see this, thanks. I started a forum thread a while back which included some ideas, that may or may not be useful.

I'm guessing takoi == @tamland?

@jimfcarroll
Copy link
Member

Is there a reason you couldn't just add this to the ModuleXbmc.h/cpp as a static methods instead of applying it through python? The only reason I didn't do it that way myself is because all of the scripts that are using the variable, but if we're changing the API anyway, why not just make the change in the module?

@tamland
Copy link
Member Author

tamland commented Aug 14, 2014

@MilhouseVH Yep

@jimfcarroll I initially tried to reuse xbmc.sleep but gave up on that because you need communicate directly with module from PythonInvoker somehow. (And no polling, @MilhouseVH is firmly against that:p). Or alternatively, if you call it via python, how would you add an instance of pythonsEvent in ModuleXbmc.h/cpp?

@jimfcarroll
Copy link
Member

I mean you would write it in terms of a CEvent and expose it in terms of several static methods on ModuleXbmc. If you can write it in a few simple C++ calls on ModuleXbmc it will "just work" in python. That way, if I ever get around to my grandiose plans of adding another scripting language it will "just work" there also.

@tamland
Copy link
Member Author

tamland commented Aug 15, 2014

Yeah, all those other languages.. Whatever happened to that?

You mean expose isSet/wait/set and keep the PythonInvoker stuff? That could work. You'll lose the nice name space though.. Did generating attributes for variables with swig ever get solved?

@Montellese
Copy link
Member

@tamland: You mean something like f113570?

@Montellese
Copy link
Member

@MartijnKaijser: not sure what you are referring to concerning JSON-RPC?

@tamland
Copy link
Member Author

tamland commented Aug 15, 2014

like that, yes.

@MartijnKaijser
Copy link
Member

@Montellese i mean that remotes for example could listen through JSON-RPC that it's going to shutdown. I see that's already added as "System.OnQuit" ? http://wiki.xbmc.org/index.php?title=JSON-RPC_API/v6#System_3

Edit: perhaps strive to having similar names for function between JSON and python if we ever would generate them from a a single source. (it was something mentioned iirc)

@Montellese
Copy link
Member

@tamland: Yeah I've added that functionality a while ago so you should be able to use it.
@MartijnKaijser: Yeah System.OnQuit is the notification that JSON-RPC uses. Ideally it should be named Application.OnQuit though because there's an Application.Quit method available.

If we want to generate JSON-RPC and python APIs from the same source we'll have to re-write the whole API. IMO in this case the new property should be named as close to the existing one as possible so e.g. abortRequestedEvent.

@tamland
Copy link
Member Author

tamland commented Aug 15, 2014

@jimfcarroll I don't think this will work. When you call the c++ library the GIL will be held until the method returns. You can't interrupt it via python. I'm guess this is why the sleep method is implemented the way it is.

@topfs2
Copy link
Contributor

topfs2 commented Aug 15, 2014

The old python code is considered legacy. So IMO if we combine json RPC and
it I'd say let's pick the best of them, and something works well for both.
We can always create a form of legacy support layer in pure python probably.
On 15 Aug 2014 12:33, "tamland" notifications@github.com wrote:

@jimfcarroll https://github.com/jimfcarroll I don't think it will work.
When you call the c++ library the GIL will be held until the method
returns. You can't interrupt it via python. I'm guess this is why the sleep
method is implemented the way it is.


Reply to this email directly or view it on GitHub
#5217 (comment).

@jimfcarroll
Copy link
Member

You have the option of whether or not to hold the GIL by using the DelayedCallGuard (it releases the GIL). If you can write it in C++ with static methods in ModuleXbmc then it will work in python.

Alternatively you can create a class called something like an AbortRequest and retrive a singleton from a static call on ModuleXbmc.

As far as those "other languages" ... I got busy with a new job. I'm sure I'll get to it after the zombie apocalypse takes care of other day-to-day issues :-) ... Every once in a while I try to figure out how to merge JSON-RPC with the python stuff and I run away with my tail between my legs. :-)

@MartijnKaijser MartijnKaijser added this to the Pending for inclusion milestone Aug 15, 2014
@jimfcarroll
Copy link
Member

Perfect. :-)

I just sat down to do this myself (of course, I was going to create an AbortRequest class but whatever).

This looks good to me. It's more verstile than setting it internal to the python vm.

Thanks. I'll let someone else merge it. 👍

*/
void stopSFX();

/**

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

@MartijnKaijser
Copy link
Member

if @jimfcarroll is ok this can go in the next merge window i guess. @tamland please include the needed python API bump.

@@ -418,7 +418,19 @@ namespace XBMCAddon
* example:
* - language = xbmc.convertLanguage(English, xbmc.ISO_639_2)
*/
String convertLanguage(const char* language, int format);
String convertLanguage(const char* language, int format);

This comment was marked as spam.

@jimfcarroll
Copy link
Member

@tamland sorry I just noticed I didn't scroll down enough. Unless I'm mistaken, the PythonInvoker::stop call doesn't need to include the CallMethod to python. You should be able to ditch the rename in the .i file and just directly call ModuleXbmc::setAbortRequested in the PythonInvoker. Am I missing somethng?

@tamland
Copy link
Member Author

tamland commented Aug 17, 2014

@jimfcarroll Yeah.. where the h is this that supposed to be declared? All this magic is making me dizzy.. Anyway, updated!:)

@MartijnKaijser
Copy link
Member

jenkins build this please

@MartijnKaijser
Copy link
Member

still missing the python API bump

@tamland
Copy link
Member Author

tamland commented Aug 19, 2014

No it's not. It's in the first commit.

@MartijnKaijser MartijnKaijser modified the milestones: Pending for inclusion, Helix 14.0-alpha4 Aug 19, 2014
@MartijnKaijser
Copy link
Member

oops. sorry that i missed that. thx.
added for merge 1 september

@MilhouseVH
Copy link
Contributor

Perhaps I've misunderstood the purpose of this PR.

With the following code as an example of a typical "service.py" addon:

...
class cxbmcm(xbmc.Monitor):
    def __init__( self, *args, **kwargs ):
        xbmc.Monitor.__init__(self)   

    def onScreensaverActivated(self):
        xbmc.log("onScreensaverActivated method called")
        # Do something screensaver-related

    def onAbortRequested(self):
        xbmc.log("onAbortRequested method called")
        # Do something clean-up related, we're about to shut down

xbmcm = cxbmcm()

if xbmc.__version__ >= "2.19.0":
  xbmc.log("Using new waitForAbort() method",)
  xbmc.waitForAbort()
else:
  xbmc.log("Using old abortRequested/sleep() method")
  while not xbmc.abortRequested:
      xbmc.sleep(100)

xbmc.log("Service terminating")

Then, when using this new waitForAbort() method, I had been expecting the onScreensaverActivated() and onAbortRequested() methods to be called as the appropriate events occur. However these methods are not being called.

They are being called when the "old" abortRequested/sleep() method is used.

Is this behaviour intentional? If so, this would mean the new waitForAbort() method will be of no benefit to those addons that intend to consume xbmc.Monitor events/notifications, and the existing abortRequested/sleep() method cannot be deprecated.

Other than that, it works nicely!

@tamland
Copy link
Member Author

tamland commented Aug 20, 2014

@jimfcarroll ?

Yeah, this isn't going to work. There's an even bigger issue: I though this was loaded for each script but it's not. It's global. Stopping one service will stop all and state is kept across executions. The original PR worked as intended (not receiving callbacks though).

@jimfcarroll
Copy link
Member

@MilhouseVH yes. I thought about this when @tamland first proposed a new abort mechanism.

Currently there are only 2 methods that ever allowed for callbacks. 'sleep' and 'doModal'. At one time I had modified this so that ANY call to a long running xbmc method had the potential to execute a callback but unfortunately several poorly written tempermental scripts broke so I put it back to only those 2.

I personally I think what your suggesting makes perfect sense and it should do that. I saw this as just a new mechanism for watching for the abort as opposed to the current boolean that's totally python specific and difficult to do in the codegenerator.

Changing this would be easy. If @tamland wants to do it then he needs to make the waitForAbort look like the ModuleXbmc::sleep method.

Look at the sleep method. To make the callbacks execute you need to call MakePendingCalls on the current "LanguageHook" but you cannot be in the scope of the "DelayedCallGuard" but you can get the current "LanguageHook" instance from it. Again, if you look at the sleep method that description should make sense.

If you want me to do it I can wait until this goes in. It should take about 10 minutes.

@jimfcarroll
Copy link
Member

Okay. How is this called on a per-script basis from within the PythonInvoker::stop method?

@tamland
Copy link
Member Author

tamland commented Aug 22, 2014

Right above where abortRequested is set...
Calls XBPython::OnAbortRequested where every Monitor instance is compared by addon id

@MilhouseVH
Copy link
Contributor

(By the way, if my testing is premature, don't hesitate to tell me to back off! ;-))

This is so nearly working perfectly, many thanks.

When using an infinite timeout, the methods are firing as they should, and the waitForAbort() method is working well, both when the system is shutting down (ie. notifying all waiting services) and also when disabling an individual service.

However, when a specific timeout value is used, disabled services begin to interact with enabled services (or maybe vice versa).

I've created two very simple services, download link. The zip contains both service.test1.addon and service.test2.addon.

All that these two services do is block on waitForAbort(), spinning round if a timeout value is set and the abort has not been requested. Activity messages will be logged until the service is aborted.

This is service.test1.addon. service.test2.addon is identical, apart from name:

# -*- coding: utf-8 -*-
import xbmc

scriptid = "service.test1.addon"
timeout  = 2.0

class cxbmcm(xbmc.Monitor):
  def __init__(self, *args, **kwargs):
    xbmc.Monitor.__init__(self)

xbmcm = cxbmcm()

xbmc.log("%s: Using new waitForAbort() method with %s timeout" \
  % (scriptid, "%f second" % timeout if timeout else "infinite"))

if timeout:
  while not xbmcm.waitForAbort(timeout):
    xbmc.log("%s: waitForAbort timedout, no abort" % scriptid)
else:
  xbmcm.waitForAbort()

xbmc.log("%s: abortRequested - shutting down" % scriptid)

You can configure the timeout value by editing the respective service.py files, setting timeout to None or a specfic time in seconds, eg. 2.0.

When both services are using a timeout value of 2.0 seconds, they should spin round logging a message until they are aborted (globally, or individually). And it should be possible to disable/abort one service, without interacting with the other service.

When service.test1.addon is disabled, it will abort as expected.

However, once service.test1.addon has been disabled, service.test2.addon will only timeout once or twice more, outputting one or two more messages, before blocking with no further timeouts.

When service.test1.addon is subsequently re-enabled, service.test2.addon will automatically resume looping at regular intervals once again.

Sample output is below, using a 2.0s timeout value. service.test1.addon is disabled, note the effect on service.test2.addon:

Event
 #1   00:59:10 1896.400757 T:2890921040  NOTICE: service.test1.addon: Using new waitForAbort() method with 2.000000 second timeout
      00:59:12 1898.401855 T:2890921040  NOTICE: service.test1.addon: waitForAbort timedout, no abort
      00:59:14 1900.403687 T:2890921040  NOTICE: service.test1.addon: waitForAbort timedout, no abort
      00:59:14 1900.703857 T:2882532432  NOTICE: service.test2.addon: Using new waitForAbort() method with 2.000000 second timeout
      00:59:16 1902.404541 T:2890921040  NOTICE: service.test1.addon: waitForAbort timedout, no abort
      00:59:16 1902.710449 T:2882532432  NOTICE: service.test2.addon: waitForAbort timedout, no abort
      00:59:18 1904.417847 T:2890921040  NOTICE: service.test1.addon: waitForAbort timedout, no abort
      00:59:18 1904.729248 T:2882532432  NOTICE: service.test2.addon: waitForAbort timedout, no abort
      00:59:20 1906.418823 T:2890921040  NOTICE: service.test1.addon: waitForAbort timedout, no abort
      00:59:20 1906.729736 T:2882532432  NOTICE: service.test2.addon: waitForAbort timedout, no abort
      ...
      00:59:58 1944.620239 T:2890921040  NOTICE: service.test1.addon: waitForAbort timedout, no abort
      00:59:58 1944.785767 T:2882532432  NOTICE: service.test2.addon: waitForAbort timedout, no abort

 #2   00:59:59 1945.552246 T:2890921040  NOTICE: service.test1.addon: abortRequested - shutting down

 #3   01:00:00 1946.786987 T:2882532432  NOTICE: service.test2.addon: waitForAbort timedout, no abort
 #4
 #5   01:00:32 1978.440308 T:2771383376  NOTICE: service.test1.addon: Using new waitForAbort() method with 2.000000 second timeout
      01:00:32 1978.791504 T:2882532432  NOTICE: service.test2.addon: waitForAbort timedout, no abort
      01:00:34 1980.440308 T:2771383376  NOTICE: service.test1.addon: waitForAbort timedout, no abort
      01:00:34 1980.791382 T:2882532432  NOTICE: service.test2.addon: waitForAbort timedout, no abort
      01:00:36 1982.440308 T:2771383376  NOTICE: service.test1.addon: waitForAbort timedout, no abort
      01:00:36 1982.791382 T:2882532432  NOTICE: service.test2.addon: waitForAbort timedout, no abort
      01:00:38 1984.440308 T:2771383376  NOTICE: service.test1.addon: waitForAbort timedout, no abort
      01:00:38 1984.791504 T:2882532432  NOTICE: service.test2.addon: waitForAbort timedout, no abort
      01:00:40 1986.440796 T:2771383376  NOTICE: service.test1.addon: waitForAbort timedout, no abort
      01:00:40 1986.791504 T:2882532432  NOTICE: service.test2.addon: waitForAbort timedout, no abort
      01:00:42 1988.441528 T:2771383376  NOTICE: service.test1.addon: waitForAbort timedout, no abort
      01:00:42 1988.791504 T:2882532432  NOTICE: service.test2.addon: waitForAbort timedout, no abort
      ...
      01:36:58 4164.701172 T:2891969616  NOTICE: service.test1.addon: waitForAbort timedout, no abort
      01:36:59 4165.524414 T:2883581008  NOTICE: service.test2.addon: waitForAbort timedout, no abort
 #6   01:36:59 4166.348145 T:2891969616  NOTICE: service.test1.addon: abortRequested - shutting down
 #7   01:37:01 4167.523438 T:2883581008  NOTICE: service.test2.addon: waitForAbort timedout, no abort
 #8
 #9   01:37:19 4185.519531 T:2883581008  NOTICE: service.test2.addon: waitForAbort timedout, no abort
      01:37:21 4187.519531 T:2883581008  NOTICE: service.test2.addon: waitForAbort timedout, no abort
 #10  01:37:21 4187.786133 T:2883581008  NOTICE: service.test2.addon: abortRequested - shutting down

Key:

#1 : xbmc.bin startup
#2 : service.test1.addon has been disabled
#3 : service.test2.addon loops only once more, apparently blocked indefinitely
#4 : 32 seconds has elapsed, with no further output from service.test2.addon
#5 : service.test1.addon is re-enabled, "releasing" service.test2.addon which immediately resumes looping

#6 : Both services are enabled, service.test1.addon is being disabled
#7 : Last output from service.test2.addon before being blocked
#8 : 18 seconds elapse with no further output from service.test2.addon - it's blocked
#9 : System (XBMC App) is shutting down, service.test2.addon is momentarily unblocked, looping twice before...
#10: ...getting the abortRequested notification, and service exits.

A possibly related issue is that if service.test1.addon is waiting with an infinite timeout, while service.test2.addon is waiting for only 2.0 seconds, then service.test2.addon will timeout very sporadically, and certainly not every 2 seconds. With such a configuration, the following is the only activity over a 5 minute period from application startup to application shutdown:

01:52:17 5083.788574 T:2882532432  NOTICE: service.test2.addon: Using new waitForAbort() method with 2.000000 second timeout
01:52:19 5085.479004 T:2890921040  NOTICE: service.test1.addon: Using new waitForAbort() method with infinite timeout
01:52:19 5085.791992 T:2882532432  NOTICE: service.test2.addon: waitForAbort timedout, no abort
01:52:21 5087.791992 T:2882532432  NOTICE: service.test2.addon: waitForAbort timedout, no abort
01:52:25 5091.804688 T:2882532432  NOTICE: service.test2.addon: waitForAbort timedout, no abort
01:52:29 5095.817871 T:2882532432  NOTICE: service.test2.addon: waitForAbort timedout, no abort
01:53:13 5139.867676 T:2882532432  NOTICE: service.test2.addon: waitForAbort timedout, no abort
01:54:17 5203.848145 T:2882532432  NOTICE: service.test2.addon: waitForAbort timedout, no abort
01:55:29 5275.859375 T:2882532432  NOTICE: service.test2.addon: waitForAbort timedout, no abort
01:57:07 5373.872559 T:2882532432  NOTICE: service.test2.addon: waitForAbort timedout, no abort
01:57:09 5375.687012 T:2890921040  NOTICE: service.test1.addon: abortRequested - shutting down
01:57:09 5375.873535 T:2882532432  NOTICE: service.test2.addon: waitForAbort timedout, no abort
01:57:10 5376.759277 T:2882532432  NOTICE: service.test2.addon: abortRequested - shutting down

@tamland
Copy link
Member Author

tamland commented Aug 23, 2014

@MilhouseVH I'm unable to reproduce this. Are you sure you aren't just seeing log catching repeated lines lol

@jimfcarroll
Copy link
Member

@MilhouseVH did you set the addon id differently in the 2 scripts?

@tamland nice job. This looks like the right solution to me - once it's working.

EDIT: @MilhouseVH - looks like you did in the scripts you zipped up.

@jimfcarroll
Copy link
Member

I could not reproduce this. It looks like it's working as intended. @MilhouseVH what platform are you on?

@jimfcarroll
Copy link
Member

@MilhouseVH when one script is running with an infinite timeout the other one is the only thing writing to the logs for long periods and since the log messages are not disambiguated the log messages will be aggregated into a "the last line repeats XXX times" message.

I think this explains what LOOKS like "sporatic" behavior.

@MilhouseVH
Copy link
Contributor

Oh wow, wow... what a muppet! :(

Yes, sorry about the rate limiting in the log - I had just been grepping it, which meant I missed the "last line repeated n times" message! D'oh.

I've now retested after adding a unique count to the log message (test ZIP updated), and this is now working as expected, in every respect! Great job!

Argh. /hides.

@tamland
Copy link
Member Author

tamland commented Aug 23, 2014

At least it's extensively tested now:D

@jimfcarroll
Copy link
Member

IMO this is good to go whenever someone wants to take it.

@MartijnKaijser
Copy link
Member

jenkins build this please
edit:
http://jenkins.xbmc.org/view/Helpers/job/BuildMulti-PR-Manually/8/

MartijnKaijser added a commit that referenced this pull request Aug 31, 2014
[python] add xbmc.abortEvent
@MartijnKaijser MartijnKaijser merged commit 8cd974e into xbmc:master Aug 31, 2014
@anaconda
Copy link
Contributor

anaconda commented Sep 2, 2014

Not sure if I'm doing it wrong, but onAbortRequested() is not called when quitting XBMC.

Diff[1]:

-    while not xbmc.abortRequested:
-        xbmc.sleep(100)
+    if xbmc.__version__ >= '2.19.0':
+        log('waitForAbort')
+        service.monitor.waitForAbort()
+    else:
+        log('while...xbmc.sleep')
+        while not xbmc.abortRequested:
+            xbmc.sleep(100)

The log file says it's using waitForAbort(). If I'm not missing something, I'd expect it to call onAbortRequested() when XBMC quits.

[1] https://github.com/xbianonpi/xbian-package-upstart-xbmc-bridge/blob/master/content/usr/local/share/xbmc/addons/script.service.xbian.upstart-bridge/service.py

@tamland
Copy link
Member Author

tamland commented Sep 2, 2014

@anaconda You won't receive callbacks after the main thread dies. It's no different from your old version. I don't think onAbortRequested have ever worked as intended.

@MilhouseVH
Copy link
Contributor

Unfortunately, this PR is the cause of a sigabrt when exiting certain screensavers (eg. Nayancat or Unary Clock).

With this PR removed, specifically b2e6e50 reverted, there is no sigabrt.

To test, install Nayancat or Unary Clock screensaver from XBMC.orgs repo. Go to Settings -> Appearance -> Screensaver, select the Nayancat/Unary Clock screensaver, then click on Preview. Wait a few seconds for the screensaver to start, then click a button/key to exit the screensaver - xbmc.bin will abort if it includes b2e6e50.

Ubuntu Backtrace (tested by fritsch on #irc): http://paste.ubuntu.com/8342961

Thread 28 (Thread 0x7fff890fa700 (LWP 7473)):
#0  0x00007ffff0439bb9 in __GI_raise (sig=sig@entry=6)
    at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
#1  0x00007ffff043cfc8 in __GI_abort () at abort.c:89
#2  0x00007ffff0476e14 in __libc_message (do_abort=do_abort@entry=1, 
    fmt=fmt@entry=0x7ffff0585668 "*** Error in `%s': %s: 0x%s ***\n")
    at ../sysdeps/posix/libc_fatal.c:175
#3  0x00007ffff04830ee in malloc_printerr (ptr=<optimized out>, 
    str=0x7ffff05857b8 "free(): corrupted unsorted chunks", action=1)
    at malloc.c:4996
#4  _int_free (av=<optimized out>, p=<optimized out>, have_lock=0)
    at malloc.c:3840
#5  0x0000000000959a58 in ADDON::CAddon::~CAddon() ()
#6  0x0000000000993524 in ADDON::CScreenSaver::~CScreenSaver() ()
#7  0x00000000019be691 in XBMCAddon::xbmcaddon::Addon::~Addon() ()
#8  0x00000000019be6e9 in XBMCAddon::xbmcaddon::Addon::~Addon() ()
#9  0x0000000000d6c926 in PythonBindings::xbmcaddon_XBMCAddon_xbmcaddon_Addon_Dealloc(PythonBindings::PyHolder*) ()
#10 0x00007ffff4f56bdf in ?? ()
   from /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0
#11 0x00007ffff4e84636 in ?? ()
   from /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0
#12 0x00007ffff4ec2497 in PyDict_DelItem ()
   from /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0
#13 0x00007ffff4f34488 in PyEval_EvalFrameEx ()
   from /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0
#14 0x00007ffff4f3917d in PyEval_EvalCodeEx ()
   from /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0
#15 0x00007ffff4f39462 in PyEval_EvalCode ()
   from /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0
#16 0x00007ffff4f39922 in PyRun_FileExFlags ()
   from /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0
#17 0x0000000000d29b56 in CPythonInvoker::execute(std::string const&, std::vector<std::string, std::allocator<std::string> > const&) ()
#18 0x0000000000d27b3e in CPythonInvoker::Execute(std::string const&, std::vector<std::string, std::allocator<std::string> > const&) ()
#19 0x0000000001a3df98 in CThread::Action() ()
#20 0x0000000001a3e659 in CThread::staticThread(void*) ()
#21 0x00007ffff6195182 in start_thread (arg=0x7fff890fa700)
    at pthread_create.c:312
#22 0x00007ffff04fdfbd in clone ()
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111

and gdb backtrace from OpenELEC/R-Pi:

[New Thread 0xb076e450 (LWP 691)]
[New Thread 0xaf5ff450 (LWP 692)]
[New Thread 0xa23ff450 (LWP 693)]
[New Thread 0xa1bff450 (LWP 695)]
[New Thread 0xa13ff450 (LWP 698)]
*** Error in `/usr/lib/xbmc/xbmc.bin': free(): corrupted unsorted chunks: 0xa37ccf90 ***
*** Error in `/usr/lib/xbmc/xbmc.bin': free(): corrupted unsorted chunks: 0xb52da498 ***

Program received signal SIGABRT, Aborted.
0xb65becf4 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:55
55      ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0  0xb65becf4 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:55
#1  0xb65c0048 in __GI_abort () at abort.c:89
#2  0xb65fb7ec in __libc_message (do_abort=<optimized out>, fmt=0xb66a8278 "*** Error in `%s': %s: 0x%s ***\n") at ../sysdeps/posix/libc_fatal.c:175
#3  0xb6601488 in malloc_printerr (action=3, str=0xb66a8414 "free(): corrupted unsorted chunks", ptr=<optimized out>) at malloc.c:4958
#4  0xb6601e30 in _int_free (av=<optimized out>, p=<optimized out>, have_lock=<optimized out>) at malloc.c:3829
#5  0x003d5b98 in release (this=0xa37c1d98)
    at /home/neil/projects/OpenELEC.tv/build.OpenELEC-RPi.arm-devel/toolchain/armv6zk-openelec-linux-gnueabi/sysroot/usr/include/boost/smart_ptr/detail/sp_counted_base_sync.hpp:128
#6  boost::detail::shared_count::~shared_count (this=0xbecff594, __in_chrg=<optimized out>)
    at /home/neil/projects/OpenELEC.tv/build.OpenELEC-RPi.arm-devel/toolchain/armv6zk-openelec-linux-gnueabi/sysroot/usr/include/boost/smart_ptr/detail/shared_count.hpp:443
#7  0x006ab270 in ~shared_ptr (this=0xbecff590, __in_chrg=<optimized out>)
    at /home/neil/projects/OpenELEC.tv/build.OpenELEC-RPi.arm-devel/toolchain/armv6zk-openelec-linux-gnueabi/sysroot/usr/include/boost/smart_ptr/shared_ptr.hpp:323
#8  CApplicationMessenger::ProcessMessages (this=0x3253ec8) at ApplicationMessenger.cpp:223
#9  0x006a4bc0 in CApplication::Process (this=0x3251518) at Application.cpp:5127
#10 0x006f6180 in CXBApplicationEx::Run (this=0x3251518) at XBApplicationEx.cpp:107
#11 0x006f9868 in XBMC_Run (renderGUI=<optimized out>) at xbmc.cpp:69
#12 0x0037d24c in main (argc=5, argv=0xbecff9c4) at main.cpp:91
(gdb)

@jimfcarroll
Copy link
Member

Wow. This is really bad and will be hard to find. I'll see what I can do today.

@tamland
Copy link
Member Author

tamland commented Sep 14, 2014

For me, Unary Clock doesn't crash at all, Nayancat does however. Looking the add-ons I have a hunch this has something to do with weird self deleting inside a callback they both do. Swig doing something weird when it's deleted early?

@tamland
Copy link
Member Author

tamland commented Sep 14, 2014

Yeah.. just add a bunch of members to the Monitor class and it will crash without this patch.

@jimfcarroll
Copy link
Member

I started looking into this. There is a double free taking place in a non-AddonClass (probably something indirectly referenced from the Monitor class or a Monitor callback). It's nasty. Turning on reference tracking and trace logging causes the problem to disappear.

I'll try to keep people posted.

@jimfcarroll
Copy link
Member

Still working on it. Adding leak and double-free detection the hard way. If anyone cares to see, I'm working here: https://github.com/jimfcarroll/xbmc/commits/scribbler-fix

@jimfcarroll
Copy link
Member

Okay. I'm pretty sure I got this: #5381

@jimfcarroll
Copy link
Member

@tamland you were right. It was the deleting inside the callback. But it wasn't SWIG, it was me. That should fix it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants