• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Troubleshooting CFMessagePort
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Troubleshooting CFMessagePort


  • Subject: Troubleshooting CFMessagePort
  • From: Jerry Krinock <email@hidden>
  • Date: Thu, 6 Jan 2011 14:42:02 -0800

I've been using CFMessagePort for interprocess communication for the last few weeks; made myself a couple little wrapper classes around CFMessagePortCreateLocal and CFMessagePortCreateRemote, implementing a "client" and "server".

I create a server only when needed and destroy it when done.  Typically, my other process will send an asychronous response.  So before sending a client message, I create a server to handle the response.  After the server's delegate receives the response, I release the server, which invalidates its port during dealloc.

Today, after some major restructuring of my app, although such a server instance works fine in one instance, in another instance, the server does not receive its callback when I send messages to it.  I've tried it with both my regular "other" process and with a little I've written, both of which both worked yesterday.  So I think something is wrong with the way I've created my server in this particular instance.  The restructuring was done in that area.

I've logged and checked the client and server port names many times in the last couple hours.  They are correct.  And, oh, I use different port names "to" and "from" my app.  (Learned that the hard way.)

Since my app does some thread gymnastics, I was wondering if maybe the thread which should get the callback is blocked.  NSLog tells me that I am inserting this server's port into the run loop of the main thread, and I believe that the main thread is not blocked.  At least it is not by design; also, when I click "Pause" in the Xcode debugger and examine the call stack of Thread-1-<com.apple.main-thread>, I see the call stack below, which looks exactly the same as what I get when my app is idle.  Although I'm not a call stack guru, I'd say that this thread is waiting for run loop sources, as desired.

Also, NSLog tells me that my server is not being deallocced.

How can I troubleshoot this?

Is there any utility to maybe probe the Mach ports that my app has open?  I can't find anything like that.

Below, I've also pasted in the code for my server class and its delegate's protocol, although I don't think the problem is in there because, again, it works fine in one instance and worked fine in all instances until today.

Thanks,

Jerry Krinock

#0	0x9472a0fa in mach_msg_trap
#1	0x9472a867 in mach_msg
#2	0x91da637f in __CFRunLoopRun
#3	0x91da5464 in CFRunLoopRunSpecific
#4	0x91da5291 in CFRunLoopRunInMode
#5	0x99520f9c in RunCurrentEventLoopInMode
#6	0x99520d51 in ReceiveNextEventCommon
#7	0x99520bd6 in BlockUntilNextEventMatchingListInMode
#8	0x98c5378d in _DPSNextEvent
#9	0x98c52fce in -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:]
#10	0x98c15247 in -[NSApplication run]
#11	0x98c0d2d9 in NSApplicationMain
#12	0x00001e52 in main at MainApp-Main.m:23


*** SSYInterappServer.h ***

#import <Cocoa/Cocoa.h>
#import "SSYInterappServerDelegate.h"

extern NSString* const SSYInterappServerErrorDomain ;

@class SSYInterappServer ;

/*!
 @brief    A server object which responds to a message sent by an
 SSYInterAppClient object from another thread or process.
*/
@interface SSYInterappServer : NSObject {
    CFMessagePortRef m_port ;
    NSObject <SSYInterappServerDelegate> * m_delegate ;
    void* m_contextInfo ;
}

/*!
 @brief    A pointer which may be used to pass information to the
 delegate

 @details  To retrieve contextInfo in the delegate method
 -interappServer:didReceiveHeaderByte:data:, send
 -contextInfo to the interappServer.
*/
@property (nonatomic, assign) void* contextInfo ;

/*!
 @brief    Designated initializer for SSYInterappServer

 @details  Uses CFMessagePort under the hood.  This port will be added
 to the current run loop in its default mode.
 @param    portName  An arbitrary name you supply, which must be unique among
 CFMessagePorts on the computer.  Suggest using a reverse DNS identifier.
 Pass this same portName when sending a message to this server from the
 SSYInterappClient class.
 @param    delegate  An object to which will be sent Objective-C messages whenever
 an interapp message is received by the receiver from a SSYInterAppClient.
 @result   The SSYInterappServer object.  When this object is released, its
 port (CFMessagePort) will be invalidated and released.
*/
- (id)initWithPortName:(NSString*)portName
              delegate:(NSObject <SSYInterappServerDelegate> *)delegate ;

@end


*** SSYInterappServer.m ***

#import "SSYInterappServer.h"


NSString* const SSYInterappServerErrorDomain =
                        @"SSYInterappServerErrorDomain" ;

@interface SSYInterappServer ()

@property (assign, nonatomic) NSObject <SSYInterappServerDelegate> * delegate ;

@end

CFDataRef SSYInterappServerCallBack(
                                    CFMessagePortRef port,
                                    SInt32 msgid,
                                    CFDataRef data,
                                    void* info) {
    NSLog(@"79051: Server received data on thread %@ %@",
      [NSThread currentThread],
       [[NSThread currentThread] isMainThread] ? @"main" : @"nonMain") ;
    // Unpack the data and send to delegate
    char headerByte = 0 ;
    if ([(NSData*)data length] > 0) {
        [(NSData*)data getBytes:&headerByte
                         length:1] ;
    }
    NSData* rxPayload = nil ;
    if ([(NSData*)data length] > 1) {
        rxPayload = [(NSData*)data subdataWithRange:
            NSMakeRange(1, [(NSData*)data length] - 1)] ;
    }

    SSYInterappServer* server = (SSYInterappServer*)info ;

    NSObject <SSYInterappServerDelegate> * delegate = [server delegate] ;
    [delegate interappServer:server
        didReceiveHeaderByte:headerByte
                        data:rxPayload] ;

    // Get response from delegate and return to Client
    NSMutableData* responseData = [[NSMutableData alloc] init];
    char responseHeaderByte = [delegate responseHeaderByte] ;
    [responseData appendBytes:(const void*)&responseHeaderByte
                       length:1] ;

    NSData* responsePayload = [delegate responsePayload] ;
    if (responsePayload) {
        [responseData appendData:responsePayload] ;
    }

    // From CFMessagePortCallBack documentation, we return the
    // "data to send back to the sender of the message.  The system
    // releases the returned CFData object."
    return (CFDataRef)responseData ;
}


@implementation SSYInterappServer

@synthesize delegate = m_delegate ;
@synthesize contextInfo = m_contextInfo ;

- (CFMessagePortRef)port {
    return m_port ;
}

- (void)dealloc {
    NSLog(@"79052: Dealloccing server %p on thread %@ %@",
        self,
        [NSThread currentThread],
        [[NSThread currentThread] isMainThread] ? @"main" : @"nonMain") ;
    CFMessagePortInvalidate(m_port) ;
    if (m_port) {
        // It is important not to leak a CFMessagePort, not only for
        // the usual reasons, but because, even though a port with a
        // given name has been invalidated, the system will still refuse
        // to create a new port with the same name until the
        // invalidated CFMessagePort has been *deallocated*.  If this
        // happens, the following message will be printed to console
        // upon invoking the next CFMessagePortCreateLocal() …
        // *** CFMessagePort: bootstrap_register(): failed 1103 (0x44f)
        // 'Service name already exists'
        // And, of course, CFMessagePortCreateLocal() will return NULL.
        CFRelease(m_port) ;
    }

    [super dealloc] ;
}

- (id)initWithPortName:(NSString*)portName
              delegate:(NSObject <SSYInterappServerDelegate> *)delegate {
    self = [super init] ;
    if (self) {
        CFMessagePortContext context ;
        context.version = 0 ;
        context.info = self ;
        context.retain = NULL ;
        context.release = NULL ;
        context.copyDescription = NULL ;

        m_port = CFMessagePortCreateLocal(
                                          NULL,
                                          (CFStringRef)portName,
                                          SSYInterappServerCallBack,
                                          &context,
                                          NULL) ;
        if (m_port) {
            NSLog(@"79050: Starting server %p with port name: %@ on thread %@ %@",
               self, portName, [NSThread currentThread],
               [[NSThread currentThread] isMainThread] ? @"main" : @"nonMain") ;
            [self setDelegate:delegate] ;
            CFRunLoopSourceRef source = CFMessagePortCreateRunLoopSource(
                                                                         NULL,
                                                                         m_port,
                                                                         0) ;
            CFRunLoopAddSource(
                               CFRunLoopGetCurrent(),
                               source,
                               kCFRunLoopDefaultMode) ;
            // Note: Leaking 'source' will also leak m_port in an apparent retain cycle.
            CFRelease(source) ;
        }
        else {
            // See http://lists.apple.com/archives/Objc-language/2008/Sep/msg00133.html ...
            [super dealloc] ;
            self = nil ;
        }
    }

    return self ;
}

@end


*** SSYInterappServerDelgate.h (Formal Protocol) ***

#import <Cocoa/Cocoa.h>

@class SSYInterappServer ;


@protocol SSYInterappServerDelegate

/*!
 @brief    This message will be received from the delegating SSYInterappServer
 whenever an interapp message is received from the SSYInterappClient class
 on another thread or process.

 @details  Immediately upon return of your implementation, and on the same thread,
 -responseHeaderByte and -responsePayload will be invoked, and the values
 you return in those methods will be used to construct a response to the interapp
 message.
 @param    server  The delegating SSYInterappServer which sent this message
 @param    headerByte  The header byte which was provided to the SSYInterappClient
 class when sending the message on the other thread or process
 @param    data  The payload data which was provided to the SSYInterappClient
 class when sending the message on the other thread or process
*/
- (void)interappServer:(SSYInterappServer*)server
  didReceiveHeaderByte:(char)headerByte
				  data:(NSData*)data ;

/*!
 @brief    The header byte which will be sent back to an SSYInterappClient
 on another thread or process in the response to an interapp message

 @details  Typically, you will implement this as the getter of a
 property.  You will set this property during your implementation of
 -interappServer:didReceiveHeaderByte:data, after computing the appropriate
 response to the given interapp message.
*/
- (char)responseHeaderByte ;

/*!
 @brief    The payload data which will be sent back to an SSYInterappClient
 on another thread or process in the response to an interapp message

 @details  Typically, you will implement this as the getter of a
 property.  You will set this property during your implementation of
 -interappServer:didReceiveHeaderByte:data, after computing the appropriate
 response to the given interapp message.
 */
- (NSData*)responsePayload ;

@end

_______________________________________________

Cocoa-dev mailing list (email@hidden)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:

This email sent to email@hidden

  • Follow-Ups:
    • Re: Troubleshooting CFMessagePort
      • From: Dave Keck <email@hidden>
  • Prev by Date: Re: NSDictionary key types
  • Next by Date: Re: How to get "colored" font smoothing in a CALayer
  • Previous by thread: Re: LOCATING MEDIA FILES IN MACINTOSH
  • Next by thread: Re: Troubleshooting CFMessagePort
  • Index(es):
    • Date
    • Thread