String.fromBytes ... fails outside the MainThread

BlitzMax Forums/BlitzMax Programming/String.fromBytes ... fails outside the MainThread

Rozek(Posted 2010) [#1]
Hello again!

Another problem in a multi-threaded application: while it is already well-known, that MaxGUI-related stuff should only be done within the MainThread - did you know that code like

incbin "Text.txt"
local Text:String = String.fromBytes(IncBinPtr("Text.txt"),IncBinLen("Text.txt"))

crashes when the assignment is made in a separate thread?

This happened to me under Mac OS X, at least (don't yet know about the other platforms)

Make the assignment in your main thread - afterwards, you may use the "Text" in any (other) thread!

Are there any other pitfalls like this one? It would be good to know...


Rozek(Posted 2010) [#2]
Hmmm,

it's probably more complicated: my application now crashes again, somewhere else, but with a similar calling chain. Here is an excerpt of the Mac OS X crash report:

Thread 4 Crashed:
0 libGL.dylib 0x92b3f96f glDeleteTextures + 59
1 Simulator.debug.mt 0x002cc3d2 533 + 0
2 Simulator.debug.mt 0x00381bf1 bbObjectFree + 28
3 Simulator.debug.mt 0x0037bde0 collectMem + 674
4 Simulator.debug.mt 0x0037b84f allocMem + 189
5 Simulator.debug.mt 0x0037c103 bbGCAllocObject + 60
6 Simulator.debug.mt 0x00381bbb bbObjectNew + 80
7 Simulator.debug.mt 0x0002d5f2 bb_processEnterFrameEvent + 65
8 Simulator.debug.mt 0x0002f07f 11093 + 43
9 Simulator.debug.mt 0x0002e091 bb_runProject + 152
10 Simulator.debug.mt 0x00219460 330 + 9
11 Simulator.debug.mt 0x0037cafa threadProc + 191
12 libSystem.B.dylib 0x90023d67 _pthread_body + 84

The pattern looks as if the Garbage Collector would be running and - somehow - invoke "glDeleteTextures" which actually crashes (before, the "String.fromBytes" expression triggered the GC in the same way)


Otus(Posted 2010) [#3]
Probably a GC induced problem and nothing to do with String.FromBytes. The GC begins to free up objects when you create the String object, and so may run any Delete methods.

To debug the specific problem you could try this debugger hack, which allows thread-debugging. (Use at own risk.)


Brucey(Posted 2010) [#4]
0 libGL.dylib 0x92b3f96f glDeleteTextures

That's interesting :-p
The GC is clearing up an object referencing some GL data which you can only affect in the main thread.
Bit of a bugger, that. Dunno how you tell the GC to free references of some objects only from the main thread.

I'd class this under "serious bug".


Rozek(Posted 2010) [#5]
Hmmm,

my problem looks somewhat similar to that mentioned in http://www.blitzmax.com/Community/posts.php?topic=88578#1005858

There, a rollback to BlitzMAX 1.34 solved the issue (for the moment, at least)

And, since that bug is a serious "stopper" for me, I'm currently trying to rollback as well...let's see how far I'll get!

[edit]
Well, BlitzMAX 1.36 still shows the same problem as described above. Currently, I can't rollback further because it turned out that I am using methods which were introduced with version 1.36 - thus, I will first have to implement alternatives for them before being able to proceed (or recede, resp.)
[/edit]

[edit]
BlitzMAX 1.35 crashes even sooner - here is an excepert of the Mac OS X crash report:

Thread 0 Crashed:
0 Simulator.debug.mt 0x0022af02 collectMem + 115
1 Simulator.debug.mt 0x0022b29e allocMem + 117
2 Simulator.debug.mt 0x0022b412 bbGCAllocObject + 51
3 Simulator.debug.mt 0x0022ef79 bbStringFromInt + 210
4 Simulator.debug.mt 0x00209983 _brl_event_TEvent_RegisterId + 74
5 Simulator.debug.mt 0x00209233 122 + 1020
6 Simulator.debug.mt 0x00205b0e 62 + 37
7 Simulator.debug.mt 0x001b58ef 195 + 37
8 Simulator.debug.mt 0x000f1ffe 1246 + 42
9 Simulator.debug.mt 0x000fb68d 306 + 37
10 Simulator.debug.mt 0x000ebc8b 946 + 57
11 Simulator.debug.mt 0x000d6c08 636 + 37
12 Simulator.debug.mt 0x000d6ba8 13 + 37
13 Simulator.debug.mt 0x000d6b48 11 + 37
14 Simulator.debug.mt 0x00005892 3010 + 1147
15 Simulator.debug.mt 0x000035d1 4 + 25
16 Simulator.debug.mt 0x00002fbd run + 77
17 com.apple.Foundation 0x927fab97 _nsnote_callback + 230
18 com.apple.CoreFoundation 0x908563d2 __CFXNotificationPost + 345
19 com.apple.CoreFoundation 0x9084db51 _CFXNotificationPostNotification + 600
20 com.apple.Foundation 0x927f3128 -[NSNotificationCenter postNotificationName:object:userInfo:] + 121
21 com.apple.Foundation 0x927fa0c9 -[NSNotificationCenter postNotificationName:object:] + 55
22 com.apple.AppKit 0x93289976 -[NSApplication _postDidFinishNotification] + 124
23 com.apple.AppKit 0x93289860 -[NSApplication _sendFinishLaunchingNotification] + 67
24 com.apple.AppKit 0x9328935d -[NSApplication(NSAppleEventHandling) _handleAEOpen:] + 273
25 com.apple.AppKit 0x93288f28 -[NSApplication(NSAppleEventHandling) _handleCoreEvent:withReplyEvent:] + 96
26 com.apple.Foundation 0x92800881 -[NSAppleEventManager dispatchRawAppleEvent:withRawReply:handlerRefCon:] + 447
27 com.apple.Foundation 0x928006ab _NSAppleEventManagerGenericHandler + 91
28 com.apple.AE 0x915237c9 aeDispatchAppleEvent(AEDesc const*, AEDesc*, unsigned long, unsigned char*) + 147
29 com.apple.AE 0x915236fa dispatchEventAndSendReply(AEDesc const*, AEDesc*) + 44
30 com.apple.AE 0x915235c6 aeProcessAppleEvent + 190
31 com.apple.HIToolbox 0x92e04084 AEProcessAppleEvent + 37
32 com.apple.AppKit 0x9328711d _DPSNextEvent + 1044
33 com.apple.AppKit 0x93286b37 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 137
34 com.apple.AppKit 0x932808c4 -[NSApplication run] + 512
35 Simulator.debug.mt 0x00003582 main + 1013
36 Simulator.debug.mt 0x000028fe _start + 216
37 Simulator.debug.mt 0x00002825 start + 41

Very early in my program, I define my own EventIds (for asynchronous thread-to-thread communication), together with a literal description - that's where BlitzMAX crashes (sigh)
[/edit]

[edit]
BlitzMax 1.34 crashes not much later than BlitzMAX 1.35 - see the crash report:

Thread 0 Crashed:
0 Simulator.debug.mt 0x00037657 _bah_cairo_TCairo_Delete + 18
1 Simulator.debug.mt 0x002260b9 collectMem + 437
2 Simulator.debug.mt 0x00226313 allocMem + 117
3 Simulator.debug.mt 0x00226487 bbGCAllocObject + 51
4 Simulator.debug.mt 0x0022a32d bbObjectNew + 34
5 Simulator.debug.mt 0x00204867 _brl_event_TEvent_Create + 101
6 Simulator.debug.mt 0x00204d33 brl_event_CreateEvent + 136
7 Simulator.debug.mt 0x0011566e 121 + 58
8 Simulator.debug.mt 0x001152a5 71 + 8
9 com.apple.Foundation 0x92849cca __NSFireTimer + 199
10 com.apple.CoreFoundation 0x9082d756 CFRunLoopRunSpecific + 3341
11 com.apple.CoreFoundation 0x9082ca42 CFRunLoopRunInMode + 61
12 com.apple.HIToolbox 0x92e01878 RunCurrentEventLoopInMode + 285
13 com.apple.HIToolbox 0x92e00f82 ReceiveNextEventCommon + 385
14 com.apple.HIToolbox 0x92e00dd9 BlockUntilNextEventMatchingListInMode + 81
15 com.apple.AppKit 0x93286f45 _DPSNextEvent + 572
16 com.apple.AppKit 0x93286b37 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 137
17 Simulator.debug.mt 0x00202f04 updateEvents + 273
18 Simulator.debug.mt 0x00202f3b bbSystemWait + 33
19 Simulator.debug.mt 0x0020372b _brl_system_TMacOSSystemDriver_Wait + 51
20 Simulator.debug.mt 0x00200dea 80 + 8
21 Simulator.debug.mt 0x00200428 5 + 35
22 Simulator.debug.mt 0x00008c8f 401 + 18
23 Simulator.debug.mt 0x00003cd1 4 + 25
24 Simulator.debug.mt 0x000036bd run + 77
25 com.apple.Foundation 0x927fab97 _nsnote_callback + 230
26 com.apple.CoreFoundation 0x908563d2 __CFXNotificationPost + 345
27 com.apple.CoreFoundation 0x9084db51 _CFXNotificationPostNotification + 600
28 com.apple.Foundation 0x927f3128 -[NSNotificationCenter postNotificationName:object:userInfo:] + 121
29 com.apple.Foundation 0x927fa0c9 -[NSNotificationCenter postNotificationName:object:] + 55
30 com.apple.AppKit 0x93289976 -[NSApplication _postDidFinishNotification] + 124
31 com.apple.AppKit 0x93289860 -[NSApplication _sendFinishLaunchingNotification] + 67
32 com.apple.AppKit 0x9328935d -[NSApplication(NSAppleEventHandling) _handleAEOpen:] + 273
33 com.apple.AppKit 0x93288f28 -[NSApplication(NSAppleEventHandling) _handleCoreEvent:withReplyEvent:] + 96
34 com.apple.Foundation 0x92800881 -[NSAppleEventManager dispatchRawAppleEvent:withRawReply:handlerRefCon:] + 447
35 com.apple.Foundation 0x928006ab _NSAppleEventManagerGenericHandler + 91
36 com.apple.AE 0x915237c9 aeDispatchAppleEvent(AEDesc const*, AEDesc*, unsigned long, unsigned char*) + 147
37 com.apple.AE 0x915236fa dispatchEventAndSendReply(AEDesc const*, AEDesc*) + 44
38 com.apple.AE 0x915235c6 aeProcessAppleEvent + 190
39 com.apple.HIToolbox 0x92e04084 AEProcessAppleEvent + 37
40 com.apple.AppKit 0x9328711d _DPSNextEvent + 1044
41 com.apple.AppKit 0x93286b37 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 137
42 com.apple.AppKit 0x932808c4 -[NSApplication run] + 512
43 Simulator.debug.mt 0x00003c82 main + 1013
44 Simulator.debug.mt 0x00002ffe _start + 216
45 Simulator.debug.mt 0x00002f25 start + 41

Thus, it always seems to be a problem related to GC...

I won't go back any further but publish a bug report instead...
[/edit]


Rozek(Posted 2010) [#6]
Hmmm,

due to the severity of the problem, I have no other chance than to dig into the foundations of BlitzMAX myself (deep sigh)

Let's see: according to the crash report

Thread 4 Crashed:
0 libGL.dylib 0x92b3f96f glDeleteTextures + 59
1 Simulator.debug.mt 0x002cc3d2 533 + 0
2 Simulator.debug.mt 0x00381bf1 bbObjectFree + 28
3 Simulator.debug.mt 0x0037bde0 collectMem + 674
4 Simulator.debug.mt 0x0037b84f allocMem + 189
5 Simulator.debug.mt 0x0037c103 bbGCAllocObject + 60
6 Simulator.debug.mt 0x00381bbb bbObjectNew + 80
7 Simulator.debug.mt 0x0002d5f2 bb_processEnterFrameEvent + 65
8 Simulator.debug.mt 0x0002f07f 11093 + 43
9 Simulator.debug.mt 0x0002e091 bb_runProject + 152
10 Simulator.debug.mt 0x00219460 330 + 9
11 Simulator.debug.mt 0x0037cafa threadProc + 191
12 libSystem.B.dylib 0x90023d67 _pthread_body + 84

"bbObjectFree" is one of the last functions called. It is found in "mod/brl.mod/blitz.mod/blitz_object.c":

void bbObjectFree( BBObject *o ){
	BBClass *clas=o->clas;
#ifdef BB_GC_RC
	if( o==&bbNullObject ){
		o->refs=BBGC_MANYREFS;
		return;
	}

	clas->dtor( o );
	bbGCDeallocObject( o,clas->instance_size );
#else
	clas->dtor( o );
#endif
}

"bbObjectFree + 28" sounds as if "clas->dtor( o );" is called which then crashes...

Is there any possibility to find out what "0x002cc3d2" refers to? (i.e. which function get's called) According to the address, it's definitely part of my program!

I am using Brucey's Cairo wrapper (which might be the reason why glDeleteTextures get's called - I definitely do not want to indicate that the wrapper is faulty - I'm just trying to find out where the app crashes...)


Rozek(Posted 2010) [#7]
Hmmm,

let's look at the other threads (just an excerpt for the moment):


Exception: EXC_BAD_ACCESS (0x0001)
Codes: KERN_PROTECTION_FAILURE (0x0002) at 0x00000ac0

Thread 0:
0 libSystem.B.dylib 0x9002447f semaphore_wait_trap + 7
1 libSystem.B.dylib 0x9011073c _sigtramp + 49
2 libSystem.B.dylib 0x90024407 semaphore_wait_signal_trap + 7
3 Simulator.debug.mt 0x0037c271 bbGCSuspend + 42
4 Simulator.debug.mt 0x00005362 164 + 24
5 Simulator.debug.mt 0x0036000c 15 + 17
6 Simulator.debug.mt 0x0035fa92 185 + 102
7 Simulator.debug.mt 0x0035caf3 390 + 92
8 Simulator.debug.mt 0x002cc9f0 615 + 31
9 Simulator.debug.mt 0x002cd6e4 _brl_glmax2d_TGLMax2DDriver_CreateFrameFromPixmap + 104
10 Simulator.debug.mt 0x002d9307 141 + 50
11 Simulator.debug.mt 0x002d1421 1296 + 15
12 Simulator.debug.mt 0x00016380 6106 + 71
13 Simulator.debug.mt 0x0000d507 4001 + 22
14 Simulator.debug.mt 0x0000f055 4469 + 248
15 Simulator.debug.mt 0x00016d3b 6253 + 24
16 Simulator.debug.mt 0x0035acfb 142 + 23
17 Simulator.debug.mt 0x00359de6 _brl_event_TEvent_Emit + 66
18 Simulator.debug.mt 0x0035a5a5 354 + 8
19 Simulator.debug.mt 0x001ec81b 216 + 74
20 Simulator.debug.mt 0x001c48d5 901 + 66
21 Simulator.debug.mt 0x001ca2a5 PostGuiEvent + 82
22 Simulator.debug.mt 0x001cc26f -[CanvasView drawRect:] + 140

What does it mean, when "bbGCSuspend" is called? Does that mean s.th. in this situation?


Otus(Posted 2010) [#8]
"bbObjectFree + 28" sounds as if "clas->dtor( o );" is called which then crashes...

Is there any possibility to find out what "0x002cc3d2" refers to? (i.e. which function get's called) According to the address, it's definitely part of my program!

That would be a call to a Delete method of some object. You could put some debug statements into different Delete methods to find out what might be going on.

If your code is not OS X specific and you want me have a look, you could send be an email.


Rozek(Posted 2010) [#9]
For a short moment,

I thought I would have found a workaround, namely not explicitly setting
setGraphicsDriver(GLMax2DDriver())

on the Mac (I still need it under Windows).

But then, my app crashed again - thread 4 again, and at a similar position as before:

Thread 4 Crashed:
0 libGL.dylib 0x92b3f96f glDeleteTextures + 59
1 Simulator.debug.mt 0x002cc3ce 533 + 0
2 Simulator.debug.mt 0x00381bed bbObjectFree + 28
3 Simulator.debug.mt 0x0037bddc collectMem + 674
4 Simulator.debug.mt 0x0037b84b allocMem + 189
5 Simulator.debug.mt 0x0037c0ff bbGCAllocObject + 60
6 Simulator.debug.mt 0x00381bb7 bbObjectNew + 80
7 Simulator.debug.mt 0x0035a17b _brl_event_TEvent_Create + 101
8 Simulator.debug.mt 0x0035a647 brl_event_CreateEvent + 136
9 Simulator.debug.mt 0x0002ee95 395 + 93
10 Simulator.debug.mt 0x0002e08a bb_runProject + 152
11 Simulator.debug.mt 0x0021945c 330 + 9
12 Simulator.debug.mt 0x0037caf6 threadProc + 191
13 libSystem.B.dylib 0x90023d67 _pthread_body + 84

But the first thread is now at a very different position:

Thread 0:
0 libSystem.B.dylib 0x9002447f semaphore_wait_trap + 7
1 libSystem.B.dylib 0x9011073c _sigtramp + 49
2 libSystem.B.dylib 0x90009817 mach_msg_trap + 7
3 com.apple.CoreFoundation 0x9082d227 CFRunLoopRunSpecific + 2014
4 com.apple.CoreFoundation 0x9082ca42 CFRunLoopRunInMode + 61
5 com.apple.HIToolbox 0x92e01878 RunCurrentEventLoopInMode + 285
6 com.apple.HIToolbox 0x92e00f82 ReceiveNextEventCommon + 385
7 com.apple.HIToolbox 0x92e00dd9 BlockUntilNextEventMatchingListInMode + 81
8 com.apple.AppKit 0x93286f45 _DPSNextEvent + 572
9 com.apple.AppKit 0x93286b37 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 137
10 Simulator.debug.mt 0x003577f0 updateEvents + 334
11 Simulator.debug.mt 0x003579d7 bbSystemWait + 40
12 Simulator.debug.mt 0x00359064 _brl_system_TMacOSSystemDriver_Wait + 51
13 Simulator.debug.mt 0x00356336 81 + 8
14 Simulator.debug.mt 0x00355974 5 + 35
15 Simulator.debug.mt 0x000087bf 401 + 18
16 Simulator.debug.mt 0x0000385d 4 + 25
17 Simulator.debug.mt 0x0000338b run + 81
18 Simulator.debug.mt 0x000035c3 -[BlitzMaxAppDelegate applicationDidFinishLaunching:] + 355


Rozek(Posted 2010) [#10]
Otus,

the problem is that I do not have any (explicit) "d'tor" which invokes "glDeleteTextures".

Is there any possibility to find out what "0x002cc3ce" refers to? It could be within the "GLMax2DDriver" or somewhere within Brucey's Cairo wrapper.


Otus(Posted 2010) [#11]
Is there any possibility to find out what "0x002cc3ce" refers to?

If I read the trace correctly, it should be a Delete method in some Type, either one defined by you or in a module. There's only one Delete method in Cairo, so that should be easily verifiable by inserting a Print or something there.

Alternatively, you could use reflection and e.g. print out the address of each Delete method to find which it might be. (This is a bit complicated. You need the _class field of the TTypeId and add the _index of the TMethod and look up the address there.)


Rozek(Posted 2010) [#12]
Otus,

great idea! Thanks - I'll try that immediately!

first Result: the "delete" method in Cairo gets indeed called - but not from the crashing thread (I would have expected a meaningful symbol in the crash report anyway in that case, but it says "533" only - does anybody know what that means? a binary compiled without debugging support?)

second result: TCairo has a method "destroy", which I modified as follows
	Method Destroy()
	debuglog("**** a")
		NoContextError()
		cairo_destroy(contextPtr)
		contextPtr = Null
	debuglog("**** b")
	End Method

Adding this pair of "debuglog" calls let my program run much longer than before(!) - although it again crashed in the end (with a report that looks similar to those mentioned above and *NOT* within the "a"..."b" pair)

Now, I would like to "trace" the routine "cairo_destroy" found in "cairo.c" - do you have any idea how I could do that? E.g., may I write to the BlitzMAX console from within that routine?

third result: I simply tried to "printf" from within "cairo_destroy" - with success! (great! printf directly writes to the output area - is the output buffered or unbuffered?) Along with some "enter"/"exit" marks I also printed the address of the routine itself: it is definitely not the mysterious "533" function! Depending on the amount of output written, the app sometimes crashes sooner, sometimes later - a typical situation in multi-threaded environments with improper synchronization (but also in environments with improper pointers!) I'm still looking for the crash reason and its solution!

fourth result: I am now able to predict when my app will crash: it is indeed within the line
clas->dtor( o );
in file "blitz_object.c" where a (still unknown) destructor is called which will finally crash my program. I can check the address of the destructor and - if the "right one" is detected - react somehow. The question is now: is there anything I can do? e.g. printing the current stack trace, entering the debugger etc? (Don't forget that I am deep in some C code!)

fifth result: if I simply avoid calling the destructor which would crash my app, the program seems to continue running fine (presumably with a memory leak, though) - it is therefore important to find out which destructor is the faulty one! The crash report mentions it as "533" which might indicate that it has been compiled without debugging support (or stems from the operating system?)


Rozek(Posted 2010) [#13]
Well,

I now have the BBClass structure of the affected objects - how do I find out their type?

Any ideas?


Rozek(Posted 2010) [#14]
Hmmm,

meanwhile, I found out how to throw an exception from within C code, which guides me directly to the debugger - but not where the object has been created, but at "waitEvent". By inspecting the object addresses within the debugger, I could not find the affected object (which is obvious as GC only removes objects that are no longer used)

Thus, I am stuck again - does anybody have an idea how I can find out which (type of) object contains the faulty destructor?


Rozek(Posted 2010) [#15]
Well, I got some results!

"BBClass" contains a field "debug_scope" which itself contains a field "name" - thus, I simply tried to print that "name" when I found the d'tor which would crash my program.

And the result of that print command was..."TGLImageFrame"!

This seems to be the type with the faulty destructor!!!!

Does anybody know this type? Surprisingly, I can't find it on my machine...is this name constructed at compile/run time and not part of some source?


plash(Posted 2010) [#16]
TGLImageFrame can be found in glmax2d.
Again, echoing others here, it seems that deconstructors are being called from alternate threads which are doing things that should not be done in said threads.
It's not a particularly easy thing to fix.


Rozek(Posted 2010) [#17]
Tim,

thanks for your hint - I found the type (in contrast to the "search" function on my Mac!?)

The problem is that I don't have any alternative: I HAVE TO find a solution (workaround or similar) or I can't continue with my development.

Let's see what I can do...


Rozek(Posted 2010) [#18]
Ok guys,

thanks for all your help - meanwhile, I have a workaround for my problem (isn't that great!?)

Here is how it works:
- instead of letting glDeleteTextures be called directly, I add a "request" with all relevant data to an "EventQueue"
- within my main thread, I repeatedly check that queue and invoke glDeleteTextures whenever necessary
As it seems, that glDeleteTextures is only rarely needed, this approach should not be too inefficient (albeit being a nasty workaround)

Here is the code (in case that anybody will need it as well):

in mod/brl.mod/glmax2d.mod/glmax2d.bmx:

- add
import brl.Threads
to the import list at the beginning
- look for the line
Type TGLImageFrame Extends TImageFrame

- just below, add
  global TexEventId:int         = allocUserEventId("glDeleteTextures Request")
  global TexEventQueue:TEvent[] = new TEvent[0]
  global TexEventMutex:TMutex   = TMutex.create()

  method enqueueTexEvent ()
    TexEventMutex.lock()
      local QueueLength:int = TexEventQueue.length
      TexEventQueue = TexEventQueue[..QueueLength+1]
      TexEventQueue[QueueLength] = createEvent(TexEventId, null, self.name)
    TexEventMutex.unlock()
  end method

  function dequeuedTexEvent:TEvent ()
    TexEventMutex.lock()
      local Result:TEvent = null

      local QueueLength:int = TexEventQueue.length
      if (QueueLength > 0) then
        Result = TexEventQueue[0]
        TexEventQueue = TexEventQueue[1..QueueLength]
      end if
    TexEventMutex.unlock()

    return Result ' might be null - that's ok!
  end function

- look for
Method Delete()

- replace the method by
	Method Delete()
		If Not seq Return

		If (seq = GraphicsSeq) then 
' 	    glDeleteTextures(1,Varptr auxName) ' crashes when called outside MainThread()
		  enqueueTexEvent()
		end if
		
		seq=0
	End Method


Then rebuild the module - it should build without problems

In your application: extend the event loop(s) in your main(!) thread as follows
    local TexEvent:TEvent = TGLImageFrame.dequeuedTexEvent()
    while (TexEvent <> null)
      local TexName:int = TexEvent.data
'     debuglog("deleting Texture #" + TexName)
      glDeleteTextures(1,Varptr TexName)

      TexEvent = TGLImageFrame.dequeuedTexEvent()
    wend

It is important, that you periodically check for pending "glDeleteTextures" requests (let's say: once a second) otherwise you just created a memory leak...

This workaround seems to work for me, but it is still...well..."suboptimal", especially, as there might be other destructors out there which might cause similar problems.

I will post a bug report in a minute


Rozek(Posted 2010) [#19]
Hmmm,

just as a side note: would it be useful to "embrace" the code snippets shown above with
?threaded
  ...
?

lines?

I have only limited insight into the way BlitzMAX-internal modules are compiled - does "?threaded" apply in such a case? Or is it mainly foreseen for compilation of applications?

Main reason for my thoughts: all the code shown above applies to multi-threaded environments only, of course, and is useless whenever only a single thread is needed.


jtfrench(Posted 2010) [#20]
wow rozek --- great analysis of this stuff. I'm going through pretty much the same problem right now and have been in desperate look for an answer as it has pretty much halted development.

Your patch makes sense, though I'm wondering if there are any other approaches to solving this. dunno yet.