File: DKEndpointManager.h

package info (click to toggle)
dbuskit 0.1.1-14
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,956 kB
  • sloc: objc: 10,543; sh: 9,463; ansic: 200; makefile: 32
file content (264 lines) | stat: -rw-r--r-- 8,492 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
/** 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]];