50using namespace blocxx;
57 bool g_useWaitpidThreadFix =
58#ifdef BLOCXX_WAITPID_THREADING_PROBLEM
66 OnceFlag g_initThreadGuard = BLOCXX_ONCE_INIT;
67 ProcessThread* g_processThread = 0;
71 Thread_t getWorkerThreadId();
77 bool rv = g_useWaitpidThreadFix;
78 g_useWaitpidThreadFix = enabled;
84 if (!g_useWaitpidThreadFix)
89 Thread_t workerThread = getWorkerThreadId();
119 NonRecursiveMutexLock lock(m_mutex);
126 NonRecursiveMutexLock lock(m_mutex);
137 NonRecursiveMutex m_mutex;
143 class WorkItem :
public IntrusiveCountableBase
150 virtual void doWork() = 0;
157 void saveException(Exception* err)
159 NonRecursiveMutexLock lock(m_errMutex);
163 Exception* getException()
165 NonRecursiveMutexLock lock(m_errMutex);
166 return m_err.getPtr();
171 NonRecursiveMutex m_errMutex;
172 WorkSignal m_doneSig;
177 class SpawnWorkItem :
public WorkItem
180 SpawnWorkItem(
char const * execPath,
char const *
const argv[],
181 char const *
const envp[], Exec::PreExec & preExec)
182 : m_execPath(execPath)
189 virtual ~SpawnWorkItem()
193 virtual void doWork()
195 NonRecursiveMutexLock lock(m_resultMutex);
196 m_result = Exec::spawnImpl(m_execPath, m_argv, m_envp, m_preExec);
201 m_doneSig.waitForSignal();
203 NonRecursiveMutexLock lock(m_resultMutex);
209 NonRecursiveMutex m_resultMutex;
211 const char * m_execPath;
212 const char *
const * m_argv;
213 const char *
const * m_envp;
214 Exec::PreExec& m_preExec;
219 class WaitpidWorkItem :
public WorkItem
222 WaitpidWorkItem(const ::pid_t& pid)
227 virtual ~WaitpidWorkItem()
231 virtual void doWork()
233 NonRecursiveMutexLock lock(m_resultMutex);
237 Process::Status waitTillDone()
239 m_doneSig.waitForSignal();
241 NonRecursiveMutexLock lock(m_resultMutex);
247 Process::Status m_result;
248 NonRecursiveMutex m_resultMutex;
250 const ::pid_t& m_pid;
253 typedef IntrusiveReference<SpawnWorkItem> SpawnWorkItemPtr;
254 typedef IntrusiveReference<WaitpidWorkItem> WaitpidWorkItemPtr;
260 virtual ~WorkQueue() {}
264 NonRecursiveMutexLock lock(m_workMutex);
268 while(m_work.empty())
270 m_workNotEmpty.wait(lock);
273 WorkItem* newWork = m_work.front();
279 void addWork(WorkItem* newWork)
281 NonRecursiveMutexLock lock(m_workMutex);
282 m_work.push(newWork);
283 m_workNotEmpty.notifyAll();
287 std::queue<WorkItem*> m_work;
288 Condition m_workNotEmpty;
289 NonRecursiveMutex m_workMutex;
296 class ProcessThread :
public Thread
300 virtual ~ProcessThread();
305 char const * exec_path,
306 char const *
const argv[],
307 char const *
const envp[],
308 Exec::PreExec & pre_exec
311 Process::Status
waitPid(
const ProcId& pid);
314 WorkQueue m_workQueue;
316 NonRecursiveMutex m_idMutex;
319 ProcessThread::ProcessThread()
323 ProcessThread::~ProcessThread()
328 Int32 ProcessThread::run()
334 newWork = m_workQueue.getWork();
342 newWork->saveException(e.clone());
344 newWork->signalDone();
351 ProcessRef ProcessThread::spawn(
char const * exec_path,
char const *
const argv[],
352 char const *
const envp[], Exec::PreExec & pre_exec)
354 SpawnWorkItemPtr newWork(
new SpawnWorkItem(exec_path, argv, envp, pre_exec));
355 m_workQueue.addWork(newWork.getPtr());
359 Exception* err = newWork->getException();
368 Process::Status ProcessThread::waitPid(
const ProcId& pid)
370 WaitpidWorkItemPtr newWork(
new WaitpidWorkItem(pid));
371 m_workQueue.addWork(newWork.getPtr());
373 Process::Status result = newWork->waitTillDone();
375 Exception* err = newWork->getException();
388 g_processThread =
new ProcessThread();
389 g_processThread->start();
392 Thread_t getWorkerThreadId()
394 callOnce(g_initThreadGuard, initThread);
395 return g_processThread->getId();
402 char const *
const argv[],
char const *
const envp[],
Exec::PreExec & pre_exec)
404 callOnce(g_initThreadGuard, initThread);
405 return g_processThread->spawn(exec_path, argv, envp, pre_exec);
410 callOnce(g_initThreadGuard, initThread);
411 return g_processThread->waitPid(pid);
This class is used to specify what spawn() should do between fork and exec.
ProcessRef spawn(char const *exec_path, char const *const argv[], char const *const envp[], PreExec &pre_exec)
Run the executable exec_path in a child process, with argv for the program arguments and envp for the...
bool sameThreads(const volatile Thread_t &handle1, const volatile Thread_t &handle2)
Check two platform dependant thread types for equality.
BLOCXX_COMMON_API ProcessRef spawnProcess(char const *exec_path, char const *const argv[], char const *const envp[], Exec::PreExec &pre_exec)
BLOCXX_COMMON_API Process::Status waitPid(const ProcId &pid)
BLOCXX_COMMON_API bool setWaitpidThreadFixEnabled(bool enabled)
If a program is single threaded (like the monitor code is), then this function can be called to ensur...
BLOCXX_COMMON_API bool shouldUseWaitpidThreadFix()
void BLOCXX_COMMON_API callOnce(OnceFlag &flag, FuncT F)
The first time callOnce is called with a given onceFlag argument, it calls func with no argument and ...
Process::Status pollStatusImpl(ProcId pid)
IntrusiveReference< Process > ProcessRef