#ifndef _H_MACHSERVER
#define _H_MACHSERVER
#include <security_utilities/mach++.h>
#include <security_utilities/timeflow.h>
#include <security_utilities/threading.h>
#include <security_utilities/globalizer.h>
#include <security_utilities/alloc.h>
#include <security_utilities/tqueue.h>
#include <set>
namespace Security {
namespace MachPlusPlus {
extern "C" {
void cdsa_mach_notify_dead_name(mach_port_t, mach_port_name_t port);
void cdsa_mach_notify_port_destroyed(mach_port_t, mach_port_name_t port);
void cdsa_mach_notify_port_deleted(mach_port_t, mach_port_name_t port);
void cdsa_mach_notify_send_once(mach_port_t);
void cdsa_mach_notify_no_senders(mach_port_t, mach_port_mscount_t);
};
class MachServer {
protected:
class LoadThread; friend class LoadThread;
struct Allocation {
void *addr;
Allocator *allocator;
Allocation(void *p, Allocator &alloc) : addr(p), allocator(&alloc) { }
bool operator < (const Allocation &other) const
{ return addr < other.addr || (addr == other.addr && allocator < other.allocator); }
};
protected:
struct PerThread {
MachServer *server;
set<Allocation> deferredAllocations;
PerThread() : server(NULL) { }
};
static ModuleNexus< ThreadNexus<PerThread> > thread;
static PerThread &perThread() { return thread()(); }
public:
MachServer();
MachServer(const char *name);
MachServer(const char *name, const Bootstrap &bootstrap);
virtual ~MachServer();
void run(mach_msg_size_t maxSize = 4096, mach_msg_options_t options = 0);
Time::Interval timeout() const { return workerTimeout; }
void timeout(Time::Interval t) { workerTimeout = t; }
UInt32 maxThreads() const { return maxWorkerCount; }
void maxThreads(UInt32 n) { maxWorkerCount = n; }
bool floatingThread() const { return useFloatingThread; }
void floatingThread(bool t) { useFloatingThread = t; }
Port primaryServicePort() const { return mServerPort; }
void add(Port receiver);
void remove(Port receiver);
static MachServer &active()
{ assert(perThread().server); return *perThread().server; }
virtual void notifyIfDead(Port port, bool doNotify = true) const;
virtual void notifyIfUnused(Port port, bool doNotify = true) const;
void releaseWhenDone(Allocator &alloc, void *memory);
void longTermActivity();
public:
class Timer : private ScheduleQueue<Time::Absolute>::Event {
friend class MachServer;
protected:
Timer(bool longTerm = false) { mLongTerm = longTerm; }
virtual ~Timer();
bool longTerm() const { return mLongTerm; }
void longTerm(bool lt) { mLongTerm = lt; }
public:
virtual void action() = 0;
Time::Absolute when() const { return Event::when(); }
bool scheduled() const { return Event::scheduled(); }
virtual void select();
virtual void unselect();
private:
bool mLongTerm; };
virtual void setTimer(Timer *timer, Time::Absolute when);
void setTimer(Timer *timer, Time::Interval offset)
{ setTimer(timer, Time::now() + offset); }
virtual void clearTimer(Timer *timer);
public:
class Handler {
public:
Handler(mach_port_t p) : mPort(p) { }
Handler() : mPort(MACH_PORT_NULL) { }
virtual ~Handler();
mach_port_t port() const { return mPort; }
virtual boolean_t handle(mach_msg_header_t *in, mach_msg_header_t *out) = 0;
protected:
void port(mach_port_t p) { assert(mPort == MACH_PORT_NULL); mPort = p; }
private:
mach_port_t mPort;
};
class NoReplyHandler : public Handler {
public:
virtual boolean_t handle(mach_msg_header_t *in) = 0;
private:
boolean_t handle(mach_msg_header_t *in, mach_msg_header_t *out);
};
void add(Handler &handler);
void remove(Handler &handler);
protected:
virtual boolean_t handle(mach_msg_header_t *in, mach_msg_header_t *out) = 0;
virtual void notifyDeadName(Port port);
virtual void notifyPortDeleted(Port port);
virtual void notifyPortDestroyed(Port port);
virtual void notifySendOnce(Port port);
virtual void notifyNoSenders(Port port, mach_port_mscount_t);
virtual void threadLimitReached(UInt32 limit);
virtual void eventDone();
Bootstrap bootstrap; ReceivePort mServerPort; PortSet mPortSet;
mach_msg_size_t mMaxSize; mach_msg_options_t mMsgOptions;
typedef set<Handler *> HandlerSet;
HandlerSet mHandlers;
protected:
void releaseDeferredAllocations();
protected:
void busy();
void idle();
void ensureReadyThread();
protected:
class LoadThread : public Thread {
public:
LoadThread(MachServer &srv) : server(srv) { }
MachServer &server;
void action(); };
Mutex managerLock; set<Thread *> workers; UInt32 workerCount; UInt32 maxWorkerCount; bool useFloatingThread;
UInt32 highestWorkerCount; UInt32 idleCount; Time::Interval workerTimeout; Time::Absolute nextCheckTime; UInt32 leastIdleWorkers; ScheduleQueue<Time::Absolute> timers;
void addThread(Thread *thread); void removeThread(Thread *thread); bool processTimer();
private:
static boolean_t handler(mach_msg_header_t *in, mach_msg_header_t *out);
void setup(const char *name);
void runServerThread(bool doTimeout = false);
friend void cdsa_mach_notify_dead_name(mach_port_t, mach_port_name_t port);
friend void cdsa_mach_notify_port_destroyed(mach_port_t, mach_port_name_t port);
friend void cdsa_mach_notify_port_deleted(mach_port_t, mach_port_name_t port);
friend void cdsa_mach_notify_send_once(mach_port_t);
friend void cdsa_mach_notify_no_senders(mach_port_t, mach_port_mscount_t);
};
} }
#endif //_H_MACHSERVER