]> git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_utilities/machserver.h
Security-179.tar.gz
[apple/security.git] / cdsa / cdsa_utilities / machserver.h
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 //
20 // machserver - C++ shell for writing Mach 3 servers
21 //
22 #ifndef _H_MACHSERVER
23 #define _H_MACHSERVER
24
25 #include <Security/mach++.h>
26 #include <Security/timeflow.h>
27 #include <Security/threading.h>
28 #include <Security/globalizer.h>
29 #include <Security/cssmalloc.h>
30 #include <Security/tqueue.h>
31 #include <set>
32
33 namespace Security {
34 namespace MachPlusPlus {
35
36
37 extern "C" {
38 void cdsa_mach_notify_dead_name(mach_port_t, mach_port_name_t port);
39 void cdsa_mach_notify_port_destroyed(mach_port_t, mach_port_name_t port);
40 void cdsa_mach_notify_port_deleted(mach_port_t, mach_port_name_t port);
41 void cdsa_mach_notify_send_once(mach_port_t);
42 void cdsa_mach_notify_no_senders(mach_port_t, mach_port_mscount_t);
43 };
44
45
46 //
47 // Mach server object
48 //
49 class MachServer {
50 class LoadThread; friend class LoadThread;
51
52 protected:
53 struct Allocation {
54 void *addr;
55 CssmAllocator *allocator;
56 Allocation(void *p, CssmAllocator &alloc) : addr(p), allocator(&alloc) { }
57 bool operator < (const Allocation &other) const
58 { return addr < other.addr || (addr == other.addr && allocator < other.allocator); }
59 };
60
61 protected:
62 struct PerThread {
63 MachServer *server;
64 set<Allocation> deferredAllocations;
65
66 PerThread() : server(NULL) { }
67 };
68 static ModuleNexus< ThreadNexus<PerThread> > thread;
69 static PerThread &perThread() { return thread()(); }
70
71 public:
72 MachServer(const char *name);
73 MachServer(const char *name, const Bootstrap &bootstrap);
74 virtual ~MachServer();
75
76 void run(size_t maxSize = 4096, mach_msg_options_t options = 0);
77
78 Time::Interval timeout() const { return workerTimeout; }
79 void timeout(Time::Interval t) { workerTimeout = t; }
80 uint32 maxThreads() const { return maxWorkerCount; }
81 void maxThreads(uint32 n) { maxWorkerCount = n; }
82
83 Port primaryServicePort() const { return mServerPort; }
84
85 // listen on additional ports (dispatching to the main handler)
86 void add(Port receiver);
87 void remove(Port receiver);
88
89 // the currently active server in this thread (there can only be one)
90 static MachServer &active()
91 { assert(perThread().server); return *perThread().server; }
92
93 // request port status notifications (override virtual methods below to receive)
94 virtual void notifyIfDead(Port port, bool doNotify = true) const;
95 virtual void notifyIfUnused(Port port, bool doNotify = true) const;
96
97 // register (CssmAllocator-derived) memory to be released after reply is sent
98 void releaseWhenDone(CssmAllocator &alloc, void *memory);
99
100 // call if you realize that your server method will take a long time
101 void longTermActivity();
102
103 public:
104 class Timer : private ScheduleQueue<Time::Absolute>::Event {
105 friend class MachServer;
106 protected:
107 virtual ~Timer() { }
108
109 public:
110 virtual void action() = 0;
111
112 Time::Absolute when() const { return Event::when(); }
113 bool scheduled() const { return Event::scheduled(); }
114 };
115
116 virtual void setTimer(Timer *timer, Time::Absolute when);
117 void setTimer(Timer *timer, Time::Interval offset)
118 { setTimer(timer, Time::now() + offset); }
119
120 virtual void clearTimer(Timer *timer);
121
122 public:
123 class Handler {
124 public:
125 Handler(mach_port_t p) : mPort(p) { }
126 Handler() : mPort(MACH_PORT_NULL) { }
127
128 mach_port_t port() const { return mPort; }
129
130 virtual boolean_t handle(mach_msg_header_t *in, mach_msg_header_t *out) = 0;
131
132 protected:
133 void port(mach_port_t p) { assert(mPort == MACH_PORT_NULL); mPort = p; }
134
135 private:
136 mach_port_t mPort;
137 };
138
139 class NoReplyHandler : public Handler {
140 public:
141 virtual boolean_t handle(mach_msg_header_t *in) = 0;
142
143 private:
144 boolean_t handle(mach_msg_header_t *in, mach_msg_header_t *out);
145 };
146
147 void add(Handler &handler);
148 void remove(Handler &handler);
149
150 protected:
151 // your server dispatch function
152 virtual boolean_t handle(mach_msg_header_t *in, mach_msg_header_t *out) = 0;
153
154 // override these to receive Mach-style port notifications about your clients
155 virtual void notifyDeadName(Port port);
156 virtual void notifyPortDeleted(Port port);
157 virtual void notifyPortDestroyed(Port port);
158 virtual void notifySendOnce(Port port);
159 virtual void notifyNoSenders(Port port, mach_port_mscount_t);
160
161 // don't mess with this unless you know what you're doing
162 Bootstrap bootstrap; // bootstrap port we registered with
163 ReceivePort mServerPort; // port to receive requests
164 PortSet mPortSet; // joint receiver port set
165
166 size_t mMaxSize; // maximum message size
167 mach_msg_options_t mMsgOptions; // kernel call options
168
169 typedef set<Handler *> HandlerSet;
170 HandlerSet mHandlers; // subsidiary message port handlers
171
172 protected:
173 void releaseDeferredAllocations();
174
175 protected:
176 class LoadThread : public Thread {
177 public:
178 LoadThread(MachServer &srv) : server(srv) { }
179
180 MachServer &server;
181
182 void action(); // code implementation
183 };
184
185 Mutex managerLock; // lock for thread-global management info below
186 set<Thread *> workers; // threads running for this server
187 uint32 workerCount; // number of worker threads (including primary)
188 uint32 maxWorkerCount; // administrative limit to workerCount
189 uint32 highestWorkerCount; // high water mark for workerCount
190 uint32 idleCount; // number of threads waiting for work
191 Time::Interval workerTimeout; // seconds of idle time before a worker retires
192 Time::Absolute nextCheckTime; // next time to check for excess threads
193 uint32 leastIdleWorkers; // max(idleCount) since last checkpoint
194 ScheduleQueue<Time::Absolute> timers;
195
196 void addThread(Thread *thread); // add thread to worker pool
197 void removeThread(Thread *thread); // remove thread from worker pool
198 bool processTimer(); // handle one due timer object, if any
199
200 private:
201 static boolean_t handler(mach_msg_header_t *in, mach_msg_header_t *out);
202 void setup(const char *name);
203 void runServerThread(bool doTimeout = false);
204
205 friend void cdsa_mach_notify_dead_name(mach_port_t, mach_port_name_t port);
206 friend void cdsa_mach_notify_port_destroyed(mach_port_t, mach_port_name_t port);
207 friend void cdsa_mach_notify_port_deleted(mach_port_t, mach_port_name_t port);
208 friend void cdsa_mach_notify_send_once(mach_port_t);
209 friend void cdsa_mach_notify_no_senders(mach_port_t, mach_port_mscount_t);
210 };
211
212
213 } // end namespace MachPlusPlus
214 } // end namespace Security
215
216 #endif //_H_MACHSERVER