2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
20 // machserver - C++ shell for writing Mach 3 servers
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>
34 namespace MachPlusPlus
{
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
);
50 class LoadThread
; friend class LoadThread
;
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
); }
64 set
<Allocation
> deferredAllocations
;
66 PerThread() : server(NULL
) { }
68 static ModuleNexus
< ThreadNexus
<PerThread
> > thread
;
69 static PerThread
&perThread() { return thread()(); }
72 MachServer(const char *name
);
73 MachServer(const char *name
, const Bootstrap
&bootstrap
);
74 virtual ~MachServer();
76 void run(size_t maxSize
= 4096, mach_msg_options_t options
= 0);
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
; }
83 Port
primaryServicePort() const { return mServerPort
; }
85 // listen on additional ports (dispatching to the main handler)
86 void add(Port receiver
);
87 void remove(Port receiver
);
89 // the currently active server in this thread (there can only be one)
90 static MachServer
&active()
91 { assert(perThread().server
); return *perThread().server
; }
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;
97 // register (CssmAllocator-derived) memory to be released after reply is sent
98 void releaseWhenDone(CssmAllocator
&alloc
, void *memory
);
100 // call if you realize that your server method will take a long time
101 void longTermActivity();
104 class Timer
: private ScheduleQueue
<Time::Absolute
>::Event
{
105 friend class MachServer
;
110 virtual void action() = 0;
112 Time::Absolute
when() const { return Event::when(); }
113 bool scheduled() const { return Event::scheduled(); }
116 virtual void setTimer(Timer
*timer
, Time::Absolute when
);
117 void setTimer(Timer
*timer
, Time::Interval offset
)
118 { setTimer(timer
, Time::now() + offset
); }
120 virtual void clearTimer(Timer
*timer
);
125 Handler(mach_port_t p
) : mPort(p
) { }
126 Handler() : mPort(MACH_PORT_NULL
) { }
128 mach_port_t
port() const { return mPort
; }
130 virtual boolean_t
handle(mach_msg_header_t
*in
, mach_msg_header_t
*out
) = 0;
133 void port(mach_port_t p
) { assert(mPort
== MACH_PORT_NULL
); mPort
= p
; }
139 class NoReplyHandler
: public Handler
{
141 virtual boolean_t
handle(mach_msg_header_t
*in
) = 0;
144 boolean_t
handle(mach_msg_header_t
*in
, mach_msg_header_t
*out
);
147 void add(Handler
&handler
);
148 void remove(Handler
&handler
);
151 // your server dispatch function
152 virtual boolean_t
handle(mach_msg_header_t
*in
, mach_msg_header_t
*out
) = 0;
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
);
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
166 size_t mMaxSize
; // maximum message size
167 mach_msg_options_t mMsgOptions
; // kernel call options
169 typedef set
<Handler
*> HandlerSet
;
170 HandlerSet mHandlers
; // subsidiary message port handlers
173 void releaseDeferredAllocations();
176 class LoadThread
: public Thread
{
178 LoadThread(MachServer
&srv
) : server(srv
) { }
182 void action(); // code implementation
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
;
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
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);
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
);
213 } // end namespace MachPlusPlus
214 } // end namespace Security
216 #endif //_H_MACHSERVER