Need Some Help with Callbacks (again) & Handler Type Def etc.

LiveCode Builder is a language for extending LiveCode's capabilities, creating new object types as Widgets, and libraries that access lower-level APIs in OSes, applications, and DLLs.

Moderators: LCMark, LCfraser

Post Reply
PaulDaMacMan
Posts: 324
Joined: Wed Apr 24, 2013 4:53 pm
Contact:

Need Some Help with Callbacks (again) & Handler Type Def etc.

Post by PaulDaMacMan » Thu Nov 19, 2020 6:44 pm

Entending LiveCode doc says this about C callback functions:
Callbacks
When used in the context of a foreign handler definition, a foreign handler type will cause automatic bridging of the LCB handler to a C function pointer which can be called directly by the native code.

The function pointers created in this fashion have lifetime equivalent to that of the calling context. In particular, for widgets they will last as long as the widget does, for all other module types they will last as long as the module is loaded.

For example, suppose you have the following function in myLib:

Code: Select all

void qsort(void base, size_t nitems, size_t size, int (compar)(const void , const void))

void c_function_with_callback(void* p_context, bool(*func)(void* p_context))
This can be bound to using the following:

Code: Select all

public foreign handler type CallbackType(in pContext as Pointer) returns CBool

foreign handler CFunctionWithCallback(in pContext as Pointer, in pHandler as CallbackType) returns nothing 
    binds to "myLib>c_function_with_callback"   

handler MyCallback(in pContext as Pointer) returns CBool
    ...

    return true
end handler

handler CallCFunctionWithCallback(in pContext as Pointer)
    CFunctionWithCallback(pContext, MyCallback)
end handler
In the language guide it says this:
Handler Types

HandlerTypeDefinition
: [ 'foreign' ] 'handler' 'type' <Name: Identifier> '(' [ ParameterList ] ')' [ 'returns' <ReturnType: Type> ]
A handler type definition defines a type which can hold a handler. Variables of such types can hold handlers (just like function pointers in C) which allows them to be called dynamically.
If the handler type is defined as foreign then automatic bridging to a C function pointer will occur when the type appears as the type of a parameter in a foreign handler definition.
Note: Passing an LCB handler to a foreign function requires creation of a function pointer. The lifetime of the function pointer is the same as the widget or module which created it.
(I really don't like the way the language guide is written, but I digress)

So I have a foreign lib with a C Function that sets a callback handler and looks something like this:

Code: Select all

cLibThingThatSetsACallback( SomeOtherThing *, handler_t, void *) 
so in psuedo-code this is:
pointer_to_new_thing (pointer to SomeOtherThing, a ref to a callback handler, nothing or pointer to OptionalSomeThing)
the callback handler in c looks like this:

Code: Select all

int (* handler_t) (void *OptionalSomeThing, incomingSecondSomthing *SecondSomething)
so in psuedo-code this is:
integer status code returned from callback handler ( along with returning nothing or a pointer OptionalSomeThing, and a pointer to incoming SecondSomthing )

I'm trying to understand how to translate all of this into LCB:

Code: Select all

public foreign handler type CallbackHandlerType(in pOptionalSomeThing as optional Pointer, in pSecondSomething as Pointer) returns CInt

foreign handler CFunctionThatSetsACallbackBinding(in tSomeOtherThing as Pointer, in pHandler as CallbackHandlerType, in pOptionalSomeThing as optional Pointer) returns nothing binds to "myLib>c_function_that_sets_a_callback"

handler MyCallbackLCBHandler(in pSomething as Pointer,in pSecondSomething as Pointer) returns CInt
   --- ...
    return true
 end handler

handler Call_CFunctionThatSetsACallbackBinding()
   variable tSomeOtherThing as Pointer
    variable tOptionalSomeThing as optional Pointer
    put nothing into tOptionalSomeThing -- void
    -- pass SomeOtherThing pointer, and the LCB Callback Handler ref, and the tOptionalSomeThing pointer:
    CFunctionThatSetsACallbackBinding(tSomeOtherThing, MyCallbackLCBHandler, tOptionalSomeThing) -
end handler
Am I getting this all right?

These are the actual c lib stuff I'm trying to deal with:

Code: Select all

fluid_midi_driver_t* new_fluid_midi_driver( fluid_settings_t * settings, handle_midi_event_func_t handler, void * event_handler_data )
typedef int(* handle_midi_event_func_t) (void *data, fluid_midi_event_t *event)
My LCB Repos: https://github.com/PaulMcClernan/

PaulDaMacMan
Posts: 324
Joined: Wed Apr 24, 2013 4:53 pm
Contact:

Re: Need Some Help with Callbacks (again) & Handler Type Def etc.

Post by PaulDaMacMan » Thu Nov 19, 2020 6:57 pm

I got it working (MIDI IN) BUT it only works once (one NoteOn message), and then stops working after that (no NoteOff message).
My LCB Repos: https://github.com/PaulMcClernan/

PaulDaMacMan
Posts: 324
Joined: Wed Apr 24, 2013 4:53 pm
Contact:

Re: Need Some Help with Callbacks (again) & Handler Type Def etc.

Post by PaulDaMacMan » Thu Nov 19, 2020 7:08 pm

AHHH HA!!!
My LCB Callback handler wasn't returning the Cint was expecting and needed that OK signal to continue!
It's working now, yeah!

Here is the working code for reference:

Code: Select all

public foreign handler type handle_midi_event_func_t( in pMyDataPtr as optional Pointer, in pMIDIEvent as Pointer) returns CInt

__safe foreign handler new_fluid_midi_driver(in pSettings as fs_SETTINGS, in pHandler as handle_midi_event_func_t, in pMyDataPtr as optional Pointer) \
																			returns optional fs_MIDIdrvr binds to "c:libfluidsynth>new_fluid_midi_driver"
__safe foreign handler delete_fluid_midi_driver(in pPlayer as fs_MIDIdrvr) returns CBool binds to "c:libfluidsynth>delete_fluid_midi_driver"
__safe foreign handler fluid_midi_event_get_type(in pMIDIEvent as fs_MIDIEvent) returns Cint binds to "c:libfluidsynth>fluid_midi_event_get_type"
__safe foreign handler fluid_midi_event_get_channel(in pMIDIEvent as fs_MIDIEvent) returns Cint binds to "c:libfluidsynth>fluid_midi_event_get_channel"
__safe foreign handler fluid_midi_event_get_key(in pMIDIEvent as fs_MIDIEvent) returns Cint binds to "c:libfluidsynth>fluid_midi_event_get_key"
__safe foreign handler fluid_midi_event_get_velocity(in pMIDIEvent as fs_MIDIEvent) returns Cint binds to "c:libfluidsynth>fluid_midi_event_get_velocity"

private handler fsHandleMIDIinput(in pMyDataPtr as optional Pointer, in pMIDIEvent as Pointer ) returns CInt
	variable tChan as Integer
	variable tMsgType as Integer
	variable tNoteNum as Integer
	variable tVelocity as Integer
	put fluid_midi_event_get_type(pMIDIEvent) into tMsgType
	put fluid_midi_event_get_channel(pMIDIEvent) into tChan
   put fluid_midi_event_get_key(pMIDIEvent) into tNoteNum
	put fluid_midi_event_get_velocity(pMIDIEvent) into tVelocity
	log [tMsgType,tChan,tNoteNum,tVelocity]
  -- 0 = kFLUID_OK:
  return 0
end handler

public handler fsInitMIDIinput(in pInputPortName as optional String) returns optional any
	if mInited then
		if pInputPortName is nothing then
			put "LC FluidSynth MIDI in" into pInputPortName
		end if
		variable tWasSet as Boolean
		variable pInputPortNameData as Data
		variable pInputPortNameDataPtr as Pointer
		variable pMIDICalbackPtr as Pointer
		put new_fluid_midi_driver(mSettings, fsHandleMIDIinput , nothing) into mMIDIDriver
	end if
end handler
My LCB Repos: https://github.com/PaulMcClernan/

PaulDaMacMan
Posts: 324
Joined: Wed Apr 24, 2013 4:53 pm
Contact:

Re: Need Some Help with Callbacks (again) & Handler Type Def etc.

Post by PaulDaMacMan » Thu Nov 19, 2020 7:14 pm

DAMN IT!
It crashes the engine when flooding the input with lots of note messages, exactly like my CoreMIDI LCB Wrapper Lib does. :(

I'm thinking this is what they call a "Dangling Pointer", the callback is using the same pointer over and over again, and then something releases it, then when it tries to use it again it crashes the engine.

Occasionally (not always) it triggers the Apple crash report window with messages like this:

Code: Select all

 Application Specific Information:
abort() called
LiveCode-Indy(2584,0x70000dbf8000) malloc: *** error for object 0x7fb54d73c7b0: pointer being freed was not allocated
 

Thread 0:: Dispatch queue: com.apple.main-thread
0   libsystem_kernel.dylib        	0x00007fff5e4f621a mach_msg_trap + 10
1   libsystem_kernel.dylib        	0x00007fff5e4f6768 mach_msg + 60
2   com.apple.CoreFoundation      	0x00007fff3243899e __CFRunLoopServiceMachPort + 328
3   com.apple.CoreFoundation      	0x00007fff32437f0c __CFRunLoopRun + 1612
4   com.apple.CoreFoundation      	0x00007fff3243766e CFRunLoopRunSpecific + 455
5   com.apple.HIToolbox           	0x00007fff316961ab RunCurrentEventLoopInMode + 292
6   com.apple.HIToolbox           	0x00007fff31695ee5 ReceiveNextEventCommon + 603
7   com.apple.HIToolbox           	0x00007fff31695c76 _BlockUntilNextEventMatchingListInModeWithFilter + 64
8   com.apple.AppKit              	0x00007fff2fa2d77d _DPSNextEvent + 1135
9   com.apple.AppKit              	0x00007fff2fa2c46b -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1361
10  com.runrev.livecode           	0x00000001073878da 0x107068000 + 3274970
11  com.runrev.livecode           	0x00000001073792f8 0x107068000 + 3216120
12  com.runrev.livecode           	0x00000001073744f2 0x107068000 + 3196146
13  com.runrev.livecode           	0x0000000107374bbe 0x107068000 + 3197886
14  com.runrev.livecode           	0x0000000107386d52 0x107068000 + 3272018
15  com.apple.Foundation          	0x00007fff346e628a __NSFireDelayedPerform + 411
16  com.apple.CoreFoundation      	0x00007fff32457810 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20
17  com.apple.CoreFoundation      	0x00007fff324573bc __CFRunLoopDoTimer + 851
18  com.apple.CoreFoundation      	0x00007fff32456f02 __CFRunLoopDoTimers + 330
19  com.apple.CoreFoundation      	0x00007fff32438112 __CFRunLoopRun + 2130
20  com.apple.CoreFoundation      	0x00007fff3243766e CFRunLoopRunSpecific + 455
21  com.apple.HIToolbox           	0x00007fff316961ab RunCurrentEventLoopInMode + 292
22  com.apple.HIToolbox           	0x00007fff31695ded ReceiveNextEventCommon + 355
23  com.apple.HIToolbox           	0x00007fff31695c76 _BlockUntilNextEventMatchingListInModeWithFilte
I have no idea how to fix it though.
My LCB Repos: https://github.com/PaulMcClernan/

PaulDaMacMan
Posts: 324
Joined: Wed Apr 24, 2013 4:53 pm
Contact:

Re: Need Some Help with Callbacks (again) & Handler Type Def etc.

Post by PaulDaMacMan » Fri Nov 20, 2020 10:53 pm

OK, so if I don't try to log incoming MIDI Messages in the LCB Extension Builder window,
and instead just pass messages to another function in the FluidSynth Library,
it doesn't crash at all, solid!

I'm thinking there is no dangling pointer crash coming from my LCB Wrapper or the FluidSynth lib,
It is either an issue thread syncing with the LC engine ( maybe not much I can do about that) ...
OR
It could be that there IS a dangling pointer crashing the engine but it's coming from the LCB Log window's code.
Which a would make this an IDE bug! I'm going to try to test that theory later.
I already have a bug report filed about this crash from working on MIDI IN on the CoreMIDI wrapper,
so if my theory proves to be true then I'll update that bug report.
My LCB Repos: https://github.com/PaulMcClernan/

Post Reply

Return to “LiveCode Builder”