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
); // legacy
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 // the currently active server in this thread (there can only be one)
84 static MachServer
&active()
85 { assert(perThread().server
); return *perThread().server
; }
87 // request dead-port notification if this port dies (override notifyDeadName)
88 virtual void notifyIfDead(Port port
) const;
90 // register (CssmAllocator-derived) memory to be released after reply is sent
91 void releaseWhenDone(CssmAllocator
&alloc
, void *memory
);
93 // call if you realize that your server method will take a long time
94 void longTermActivity();
97 class Timer
: private ScheduleQueue
<Time::Absolute
>::Event
{
98 friend class MachServer
;
103 virtual void action() = 0;
105 Time::Absolute
when() const { return Event::when(); }
106 bool scheduled() const { return Event::scheduled(); }
109 virtual void setTimer(Timer
*timer
, Time::Absolute when
);
110 void setTimer(Timer
*timer
, Time::Interval offset
)
111 { setTimer(timer
, Time::now() + offset
); }
113 virtual void clearTimer(Timer
*timer
);
118 Handler(mach_port_t p
) : mPort(p
) { }
119 Handler() : mPort(MACH_PORT_NULL
) { }
121 mach_port_t
port() const { return mPort
; }
123 virtual boolean_t
handle(mach_msg_header_t
*in
, mach_msg_header_t
*out
) = 0;
126 void port(mach_port_t p
) { assert(mPort
== MACH_PORT_NULL
); mPort
= p
; }
132 class NoReplyHandler
: public Handler
{
134 virtual boolean_t
handle(mach_msg_header_t
*in
) = 0;
137 boolean_t
handle(mach_msg_header_t
*in
, mach_msg_header_t
*out
);
140 void add(Handler
&handler
);
141 void remove(Handler
&handler
);
144 // your server dispatch function
145 virtual boolean_t
handle(mach_msg_header_t
*in
, mach_msg_header_t
*out
) = 0;
147 // override these to receive Mach-style port notifications about your clients
148 virtual void notifyDeadName(Port port
);
149 virtual void notifyPortDeleted(Port port
);
150 virtual void notifyPortDestroyed(Port port
);
151 virtual void notifySendOnce();
153 // don't mess with this unless you know what you're doing
154 Bootstrap bootstrap
; // bootstrap port we registered with
155 ReceivePort mServerPort
; // port to receive requests
156 PortSet mPortSet
; // joint receiver port set
158 size_t mMaxSize
; // maximum message size
159 mach_msg_options_t mMsgOptions
; // kernel call options
161 typedef set
<Handler
*> HandlerSet
;
162 HandlerSet mHandlers
; // subsidiary message port handlers
165 void releaseDeferredAllocations();
168 class LoadThread
: public Thread
{
170 LoadThread(MachServer
&srv
) : server(srv
) { }
174 void action(); // code implementation
177 Mutex managerLock
; // lock for thread-global management info below
178 set
<Thread
*> workers
; // threads running for this server
179 uint32 workerCount
; // number of worker threads (including primary)
180 uint32 maxWorkerCount
; // administrative limit to workerCount
181 uint32 highestWorkerCount
; // high water mark for workerCount
182 uint32 idleCount
; // number of threads waiting for work
183 Time::Interval workerTimeout
; // seconds of idle time before a worker retires
184 Time::Absolute nextCheckTime
; // next time to check for excess threads
185 uint32 leastIdleWorkers
; // max(idleCount) since last checkpoint
186 ScheduleQueue
<Time::Absolute
> timers
;
188 void addThread(Thread
*thread
); // add thread to worker pool
189 void removeThread(Thread
*thread
); // remove thread from worker pool
190 bool processTimer(); // handle one due timer object, if any
193 static boolean_t
handler(mach_msg_header_t
*in
, mach_msg_header_t
*out
);
194 void setup(const char *name
);
195 void runServerThread(bool doTimeout
= false);
197 friend void cdsa_mach_notify_dead_name(mach_port_t
, mach_port_name_t port
);
198 friend void cdsa_mach_notify_port_destroyed(mach_port_t
, mach_port_name_t port
);
199 friend void cdsa_mach_notify_port_deleted(mach_port_t
, mach_port_name_t port
);
200 friend void cdsa_mach_notify_send_once(mach_port_t
);
204 } // end namespace MachPlusPlus
206 } // end namespace Security
208 #endif //_H_MACHSERVER