how to access kCFRunLoopDefaultMode

Just starting out? Need help? Post your questions and find answers here.
User avatar
mariosk8s
Enthusiast
Enthusiast
Posts: 103
Joined: Wed Apr 06, 2011 11:37 am
Location: Hüfingen, Germany
Contact:

how to access kCFRunLoopDefaultMode

Post by mariosk8s »

I'm trying to do some fsevents work on the mac, and it's not working with me.
As soon as a file system event arrives, it takes a dump.

Below is stripped down version of my code trying to implement this

Code: Select all

EnableExplicit
ImportC "-framework CoreServices"
  CFStringCreateWithCharacters.i (*alloc, *bytes, numChars.i)
  CFArrayCreate.i(*allocator, *values, numValues.i, *callBacks)
  FSEventStreamCreate(*allocator, *callback, *context, *pathsToWatch, sinceWhen.q, latency.d, flags.l)
  FSEventStreamScheduleWithRunLoop(*streamRef, *runLoop, *runLoopMode)
  FSEventStreamStart(*streamRef)
  CFRunLoopRun()
  CFRunLoopGetCurrent.i()
  FSEventStreamInvalidate(*streamRef)
  FSEventStreamRelease(*streamRef)
EndImport

#kCFStringEncodingMacRoman = 0
#kFSEventStreamCreateFlagNone  = $00000000
#kFSEventStreamEventIdSinceNow = $FFFFFFFFFFFFFFFF

Global kCFRunLoopDefaultModeStr.s = "kCFRunLoopDefaultMode"
Global kCFRunLoopDefaultMode.i = CFStringCreateWithCharacters(#Null, 
               @kCFRunLoopDefaultModeStr, Len(kCFRunLoopDefaultModeStr))
 
Procedure callback(*stream, *ctx, numEvents.i, *eventPaths, *eventFlags_l, *eventIds_q)
  PrintN("callback")
EndProcedure

Procedure main(filePath.s)
  PrintN("Watching " + filePath)
  Protected *strRef = CFStringCreateWithCharacters(#Null, @filePath, 
                                                   Len(filePath))
  Protected *pathsToWatch = CFArrayCreate(#Null, @*strRef, 1, #Null)
  Protected latency.d = 1.0 ; Latency in seconds
  Protected *stream = FSEventStreamCreate(#Null, @callback(), #Null, *pathsToWatch,
                                #kFSEventStreamEventIdSinceNow, latency, 
                                #kFSEventStreamCreateFlagNone)
  FSEventStreamScheduleWithRunLoop(*stream, CFRunLoopGetCurrent(), 
                                   kCFRunLoopDefaultMode)
  FSEventStreamStart(*stream)
  PrintN("entering CFRunLoop");
  CFRunLoopRun()
  PrintN("exited CFRunLoop");

  FSEventStreamInvalidate (*stream)
  FSEventStreamRelease (*stream)
EndProcedure

main("/")
Assuming this code is in the notorious foo.pb, i run the following

Code: Select all

$ pbcompiler -ds -c -u -t -e foo foo.pb && lldb foo

******************************************
PureBasic 5.24 LTS (MacOS X - x86)
******************************************

Loading external modules...
Starting compilation...
47 lines processed.
Creating the executable.

- Feel the ..PuRe.. Power -

Current executable set to 'foo' (i386).
(lldb) r
Process 65891 launched: '/Users/regify/src/apps/regibox/foo' (i386)
Watching /
entering CFRunLoop
callback
Process 65891 stopped
* thread #1: tid = 0x104cea, 0x00000001, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x1)
    frame #0: 0x00000001
error: memory read failed for 0x0
(lldb) bt all
* thread #1: tid = 0x104cea, 0x00000001, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x1)
  * frame #0: 0x00000001

  thread #2: tid = 0x104d00, 0x90928992 libsystem_kernel.dylib`kevent64 + 10, queue = 'com.apple.libdispatch-manager'
    frame #0: 0x90928992 libsystem_kernel.dylib`kevent64 + 10
    frame #1: 0x984d9899 libdispatch.dylib`_dispatch_mgr_invoke + 238
    frame #2: 0x984d9532 libdispatch.dylib`_dispatch_mgr_thread + 52
In http://www.opensource.apple.com/source/ ... nLoop.h:68 is the following declaration

Code: Select all

CF_EXPORT const CFStringRef kCFRunLoopDefaultMode;
I have a working C sample for this, but it's using the original kCFRunLoopDefaultMode instead of my homegrown one.
Is there a way to access the original one?

When i did a home grown kCFRunLoopDefaultMode in the C sample, it failed to get events, but didn't crash.

Any other things, that stick out as sinfully wrong here?
I've been banging my head against this for 2 days now :cry:
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: how to access kCFRunLoopDefaultMode

Post by wilbert »

Does this work ?

Code: Select all

EnableExplicit
OpenConsole()

ImportC ""
  CFSTR(cStr.p-ascii) As "___CFStringMakeConstantString"
  FSEventStreamCreate(*allocator, *callback, *context, *pathsToWatch, sinceWhen.q, latency.d, flags.l)
  FSEventStreamScheduleWithRunLoop(*streamRef, *runLoop, *runLoopMode)
  FSEventStreamStart(*streamRef)
  FSEventStreamStop(*streamRef)
  CFRunLoopRun()
  CFRunLoopGetCurrent.i()
  FSEventStreamInvalidate(*streamRef)
  FSEventStreamRelease(*streamRef)
EndImport

#kFSEventStreamCreateFlagNone  = $00000000
#kFSEventStreamEventIdSinceNow = $FFFFFFFFFFFFFFFF

Global kCFRunLoopDefaultMode.i = CFSTR("kCFRunLoopDefaultMode")
 
ProcedureC callback(*stream, *ctx, numEvents.i, *eventPaths, *eventFlags_l, *eventIds_q)
  PrintN("callback")
EndProcedure

Procedure main(filePath.s)
  PrintN("Watching " + filePath)
  Protected *pathsToWatch = CocoaMessage(0, 0, "NSArray arrayWithObject:$", @filePath)
  Protected latency.d = 1.0 ; Latency in seconds
  Protected *stream = FSEventStreamCreate(#Null, @callback(), #Null, *pathsToWatch,
                                #kFSEventStreamEventIdSinceNow, latency, 
                                #kFSEventStreamCreateFlagNone)
  FSEventStreamScheduleWithRunLoop(*stream, CFRunLoopGetCurrent(), 
                                   kCFRunLoopDefaultMode)
  FSEventStreamStart(*stream)
  PrintN("entering CFRunLoop");
  CFRunLoopRun()
  PrintN("exited CFRunLoop");

  FSEventStreamStop(*stream)
  FSEventStreamInvalidate (*stream)
  FSEventStreamRelease (*stream)
EndProcedure

main("/")
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
mariosk8s
Enthusiast
Enthusiast
Posts: 103
Joined: Wed Apr 06, 2011 11:37 am
Location: Hüfingen, Germany
Contact:

Re: how to access kCFRunLoopDefaultMode

Post by mariosk8s »

Awesome @wilbert, you're a life saver.
Thank you :D
One last question. Should i

Code: Select all

CFRelease(*pathsToWatch)
and if so can i do this right after FSEventStreamCreate, or does it need to hang around for the life time of the stream?
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: how to access kCFRunLoopDefaultMode

Post by wilbert »

mariosk8s wrote:One last question. Should i

Code: Select all

CFRelease(*pathsToWatch)
and if so can i do this right after FSEventStreamCreate, or does it need to hang around for the life time of the stream?
It's a NSArray instead of a CFArray. Some type of objects can be 'Toll-Free Bridged' meaning you can pass a NSArray when a CFArray is expected and the other way around. This is also the case for NSString and CFString.
Since it's a NSArray you don't use CFRelease.
In its current form it is an autorelease object. In a gui application those are automatically released when the autorelease pool PureBasic creates is drained.
If you want to handle things manually, change the line that creates the array to

Code: Select all

Protected *pathsToWatch = CocoaMessage(0, CocoaMessage(0, 0, "NSArray alloc"), "initWithObject:$", @filePath)
and release it like this

Code: Select all

CocoaMessage(0, *pathsToWatch, "release")
I seems to be working to do it right after FSEventStreamCreate but if you want to be sure you can also do it after the stream is released.
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
mariosk8s
Enthusiast
Enthusiast
Posts: 103
Joined: Wed Apr 06, 2011 11:37 am
Location: Hüfingen, Germany
Contact:

Re: how to access kCFRunLoopDefaultMode

Post by mariosk8s »

Ah, so if i read your post right, then it's best to just leave it alone, as there will only be one path in there for me. So resource consumption is not an issue.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: how to access kCFRunLoopDefaultMode

Post by wilbert »

mariosk8s wrote:Ah, so if i read your post right, then it's best to just leave it alone, as there will only be one path in there for me. So resource consumption is not an issue.
In that case you can indeed leave it as it is. :)
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
mariosk8s
Enthusiast
Enthusiast
Posts: 103
Joined: Wed Apr 06, 2011 11:37 am
Location: Hüfingen, Germany
Contact:

Re: how to access kCFRunLoopDefaultMode

Post by mariosk8s »

Thanks for your help, wilbert.
Post Reply