darling-dbuskit/Source/DKEndpointManager.h
Niels Grewe ab2546c5b4 Implement recovery of D-Bus connections for the bus objects.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/dbuskit/trunk@32237 72102866-910b-0410-8b05-ffd578937521
2011-02-19 21:44:56 +00:00

265 lines
8.3 KiB
Objective-C

/** Declaration of DKEndpointManager class that manages D-Bus endpoints.
Copyright (C) 2011 Free Software Foundation, Inc.
Written by: Niels Grewe <niels.grewe@halbordnung.de>
Created: January 2011
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02111 USA.
*/
#import <Foundation/NSObject.h>
#include <stdint.h>
#include <dbus/dbus.h>
@class DKEndpoint, DKProxy, NSLock, NSMapTable, NSThread, NSRecursiveLock;
// The structure members should all be of the same size, so the compiler should
// not do any awkward packing.
typedef struct {
id target;
SEL selector;
id object;
intptr_t* returnPointer;
} DKRingBufferElement;
/**
* DKEndpointManager is a singleton class that maintains a thread to interact
* with D-Bus. It is responsible for creating and tracking the endpoints to
* the specific busses and will attempt to recover from connection failures.
*
* DKEndpointManager also provides a synchronized mode so that it can be safely
* called from +initialize methods. In that case, the caller is expected to wrap
* method calls that might trigger the manager (especially to DKEndpoint,
* DKPort, DKPortNameServer, DKProxy, or DKNotificationCenter) with calls to
* -enterInitialize and -leaveInitialize.
*/
@interface DKEndpointManager: NSObject
{
/**
* The thread running the runloop which interacts with libdbus.
*/
NSThread *workerThread;
@private
/**
* Tracks whether the thread has been started.
*/
BOOL threadStarted;
/**
* Tracks whether we already enabled threading.
*/
BOOL threadEnabled;
/**
* Maps active DBusConnections to the corresponding DKEndpoints.
*/
NSMapTable *activeConnections;
/**
* Lock to protect changes to the connection tables.
*/
NSRecursiveLock *connectionStateLock;
/**
* A (oneway) ring buffer for queuing tuples of the following form:
* <target, selector, data, pointer-to-return>. The tuples are inserted
* whenever a libdbus callback requires a value to be returned from the worker
* thread.
*/
DKRingBufferElement *ringBuffer;
/**
* Free-running counter for the producer threads
*/
uint32_t producerCounter;
/**
* Since it is possible for more than one thread to write to the ring buffer,
* it cannot be completely lockless: Producers need to obtain the
* <ivar>producerLock</ivar> in order to prevent overwriting. Since there is
* only one consumer thread, it needs no such provisions.
*/
NSLock *producerLock;
/**
* Free-running counter for the consumer thread
*/
uint32_t consumerCounter;
/**
* Counter to track how many callers are calling into the endpoint-manager
* from +initialize.
*/
NSUInteger initializeRefCount;
/**
* Lock to protect changes to the accounting tables in synchronised mode.
*/
NSRecursiveLock *synchronizationStateLock;
/**
* The <ivar>syncedWatchers</ivar> map table keeps track of watchers that were
* created while the endpoint manager is in synchronised mode. Each is mapped
* to the thread it was created in. When the last +initialize call using the
* manager finishes, the manager will reap these watchers and reschedule them
* on the worker thread.
*/
NSMapTable *syncedWatchers;
/**
* The <ivar>syncedTimers</ivar> map table keeps track of watchers that were
* created while the endpoint manager is in synchronised mode. Each is mapped
* to the thread it was created in. When the last +initialize call using the
* manager finishes, the manager will invalidate these timers and reschedule
* then on the worker thread.
*/
NSMapTable *syncedTimers;
}
/**
* Returns the shared endpoint manager that is used to manage interactions with
* libdbus.
*/
+ (id)sharedEndpointManager;
/**
* Returns a reference to the worker thread that interacts with D-Bus.
*/
- (NSThread*)workerThread;
/**
* Creates or reuses an endpoint.
*/
- (id)endpointForDBusConnection: (DBusConnection*)connection
mergingInfo: (NSDictionary*)info;
/**
* Returns an endpoint connected to an arbitrary address. This is only useful
* for specific cases where you don't want to use one of the standard message
* busses. Use -endpointForWellKnownBus: to get a connection for one of those.
*/
- (DKEndpoint*)endpointForConnectionTo: (NSString*)address;
/**
* Returns an endpoint connected to one of the well-known message busses as per
* D-Bus documentation (i.e. DBUS_BUS_SYSTEM, DBUS_BUS_SESSION or
* DBUS_BUS_STARTER).
*/
- (DKEndpoint*)endpointForWellKnownBus: (DBusBusType)type;
/**
* Method to be called by endpoints that are being deallocated.
*/
- (void)removeEndpointForDBusConnection: (DBusConnection*)connection;
/**
* Entry point for the worker thread.
*/
- (void)start: (id)ignored;
/**
* Schedules periodic recovery attempts for <var>endpoint/var>. Will be used in
* case of bus failures. If recovery is successful, <var>aProxy</var> will be
* notified.
*/
- (void)attemptRecoveryForEndpoint: (DKEndpoint*)endpoint
proxy: (DKProxy*)aProxy;
/**
* Inserts the request into the ring buffer and schedules it for draining in the
* worker thread. With <var>doWait</var> set to YES this method becomes a
* synchonisation point: It will spin until the request has completed. This
* should only be used when a return value is required by the libdbus API.
*/
- (BOOL)boolReturnForPerformingSelector: (SEL)selector
target: (id)target
data: (void*)data
waitForReturn: (BOOL)doWait;
/**
* Called from within the worker thread to process requests from the ring
* buffer.
*/
- (void)drainBuffer: (id)ignored;
/**
* Will be called in order to enable threaded mode.
*/
- (void)enableThread;
/**
* Will be called by DBusKit classes that require usage of the bus in their
* +initialize method.
*/
- (void)enterInitialize;
/**
* Will be called by DBusKit classes that require usage of the bus in their
* +initialize method.
*/
- (void)leaveInitialize;
/**
* This method can be used to determine whether the manager is in synchronized
* mode due to being called from an initialize method.
*/
- (BOOL)isSynchronizing;
/**
* This method will be used by instances of <class>DKRunLoopContext</class> to
* inform the endpoint manager of timers it is presently using. If the manager
* is in synchronized mode (i.e. being called from +initialize), a reference to
* the timer will be tracked until it either no longer needed or has
* successfully been rescheduled on the worker thread. In order to track all
* data required, the <var>context</var> the timer comes from must be specified.
*/
- (void)registerTimer: (id)timer
fromContext: (id)context;
/**
* This method will be used by instances of <class>DKRunLoopContext</class> to
* inform the endpoint manager of <class>DKWatcher</class> instances it is
* presently using to monitor file descriptors on behalf of libdbus. If the manager
* is in synchronized mode (i.e. being called from +initialize), a reference to
* the watcher will be tracked until it either no longer needed or has
* successfully been rescheduled on the worker thread.
*/
- (void)registerWatcher: (id)watcher;
/**
* If the receiver is in synchronized mode, this removes the reference to the
* timer object.
*/
- (void)unregisterTimer: (id)timer;
/**
* If the receiver is in synchronized mode, this removes the reference to the
* watcher object.
*/
- (void)unregisterWatcher: (id)watcher;
@end
/**
* Macro to check whether the code is presently executing in the worker thread
*/
#define DKInWorkerThread (BOOL)[[[DKEndpointManager sharedEndpointManager] workerThread] isEqual: [NSThread currentThread]];