Dialog hanging the window sometimes

Hello,

I have a rather large pyROOT based GUI program. I decided to make use of a file dialog displayed on a menu selection. Here is the responsible part of the code:

		# Save currend PDM display to a file
		elif menuId == widgetsIds.mSaveDisplay:
			#"""
			ROOT.gROOT.ProcessLine("fi = TGFileInfo();")
			ini_dir = '.'
			ROOT.gROOT.ProcessLine("fi.fIniDir = (char*)malloc(%d);" % (len(ini_dir)+1))
			ROOT.fi.fIniDir = ini_dir
			self.file_dialog = ROOT.TGFileDialog(ROOT.gClient.GetRoot(), self, ROOT.kFDSave, ROOT.fi)
			ROOT.gPad.SaveAs(self.fi.fFilename)
			"""
			self.fi = ROOT.TGFileInfo()
			file_dialog = ROOT.TGFileDialog(ROOT.gClient.GetRoot(), self, ROOT.kFDSave, self.fi)
			ROOT.SetOwnership(file_dialog, False)
			print self.fi.fFilename, ROOT.gPad
			ROOT.gPad.SaveAs(self.fi.fFilename)
			print "saved"
			"""
			del self.file_dialog

however, the code works… randomly. Sometimes saves the file and the program continues to work normally, sometimes does not save the file and freezes the GUI. It happens similarily in both the uncommented and commented parts. Can you derive from this code snippet what am I doing wrong?

Hi,

there has been some work in fixing locking to handle thread safety. PyROOT has always locked CINT before calling. There are multiple layers of callbacks (through CINT) in your code.

Which version of ROOT are you using? There are a few recent version that are affected (basically between those extra locks going in, and them being removed from PyROOT).

Of course, it could also be something completely different …

Cheers,
Wim

5.34.15.

I wonder, if I can make this very simple saving in a safe way?

Hi,

5.34.15 should not have the problem that I was thinking about.

The biggest problem is probably with ProcessLine(). Is there any way you can do without? Or rather, why is it used in the first place? The TGFileInfo() call gives a warning, but that can be suppressed if you like. Instead of malloc, you can use an array.array of type ‘c’.

Cheers,
Wim

I can use just the part of code without ProcesLine:

         self.fi = ROOT.TGFileInfo()
         file_dialog = ROOT.TGFileDialog(ROOT.gClient.GetRoot(), self, ROOT.kFDSave, self.fi)
         ROOT.SetOwnership(file_dialog, False)
         print self.fi.fFilename, ROOT.gPad
         ROOT.gPad.SaveAs(self.fi.fFilename)
         print "saved"

but the result is the same - sometimes it hangs, sometimes it doesn’t…

Hi,

then I have no further ideas. You can run under gdb and get all the stack traces of the individual threads to find out where the block is. Maybe there’s something obvious in there.

Otherwise, I’d have to be able to reproduce this (i.e. need some code that exhibits the problem).

Cheers,
Wim

I am not sure how to debug pyROOT script with GDB, so I removed 99% of my code and still having the same behaviour. I attach the file. If you could please try it. Just run and select from menu “Save display” and than save as, for example, 1.png.

Sometimes it takes more than 10 attempts to save/quit/save/quit… until it hangs, sometimes it hangs on the first attempt.
etos.py (4.71 KB)

Hi,

thanks for the script. I get a:*** Error in `python': corrupted double-linked list: 0x00007f74ec292890 ***Ouch. I’ll do some digging.

Cheers,
Wim

Hi,

I know this line is commented out, but just for the record/those who come after:ROOT.gROOT.ProcessLine("fi.fIniDir = (char*)malloc(%d);" % (len(ini_dir)+1))fIniDir is actually deleted with delete[], so it needs to be allocated with new[].

Cheers,
Wim

Do you get an error just when running or when trying to save? The script is quite simple, but who knows…

For the malloc - I got this code snippet somewhere in this forum :slight_smile:

Yes, the error is when creating the TGFileDialog. Valgrind claims bad writes onto the newly created object. I don’t understand that. I figured it might have something to do with a failing cast (the object has multiple inheritance op its ancestor tree, and CINT can’t handle that, unless the offset is zero; as it happens, that is the case, though).

Later,
Wim

Can I do anything to help debug this problem?

Not sure, as I do not understand the valgrind reports myself yet. I expect to have some more time for it today, though.

Cheers,
Wim

Well, I can see now what is going on, but don’t know yet what to do about it.

Here’s what’s happening: the constructor of the TGFileDialog runs the whole dialog business and at the end of that, the dialog object gets deleted. Only then does the constructor return, and so the object handed to python is deleted already. The memory regulator, thinking it is a fresh object, then scribbles in that deleted space (getting valgrind up in arms) by calling its SetBit() method. That scribbling itself is not a problem, as there is insufficient code in between to have the memory reused, but it is at the start of the object, and thus overwriting malloc’s memory management info.

Pfff …

Best workaround I can think of, is to call new TGFileDialog on a gROOT.ProcessLine(), so that there is never a Python side object for the file dialog. Or better yet, do all of that in a C++ helper.

Cheers,
Wim

I tried to do in the helper, unfortunately I get “error: ‘fi’ does not name a type”, where fi is TGFileInfo. I confirmed, that the code works in standalone CINT. I attach the helper.
save_display.C (609 Bytes)

Hi,

it’s a limitation of CINT that it can not define functions at run-time. This is fixed with Cling in ROOT6, or use of ACLiC with CINT.

However, I think this may be the simplest:fi = ROOT.gROOT.ProcessLine("TGFileInfo* fi = new TGFileInfo; new TGFileDialog(gClient->GetRoot(), gClient->GetRoot(), kFDSave, fi); fi;") self.fi = ROOT.BindObject(fi, ROOT.TGFileInfo) ROOT.SetOwnership(self.fi, True) ROOT.gPad.SaveAs(self.fi.fFilename)
Cheers,
Wim

Thanks, works!

However, I have to questions:

  1. What do you mean by “use ACLIC”? I was executing my command with “+”, so it is compiled - I thought that is using ACLIC.
  2. I guess there is no way of getting rid of the nasty
/opt/root/lib/ROOT.py:469: RuntimeWarning: creating converter for unknown type "const char**"
  attr = _root.LookupRootEntity( name )

message?

Hi,

I didn’t see a callable method in the .C, so I wouldn’t expect that the work with ACLiC, so that’s why I assumed you used CINT rather. Doesn’t matter.

To suppress the warning, do:import warnings warnings.filterwarnings( action='ignore', category=RuntimeWarning, \ message='creating converter for unknown type "const char\*\*"' )
Cheers,
Wim

Thanks again!