/* +----------------------------------------------------------------------+ | HipHop for PHP | +----------------------------------------------------------------------+ | Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ */ #ifndef __CONCURRENCY_ASYNC_FUNC_H__ #define __CONCURRENCY_ASYNC_FUNC_H__ #include "base.h" #include #include "synchronizable.h" #include "lock.h" #include "exception.h" #include "alloc.h" namespace HPHP { /////////////////////////////////////////////////////////////////////////////// /** * Invokes a function asynchrously. For example, * * class MyClass { * public: * void doJob(); * }; * * MyClass obj; * AsyncFunc func(&obj, &MyClasss::doJob); * func.start(); // this will call obj.doJob() in a separate thread * // do something else * func.waitForEnd(); * * Asynchronous function is a slightly different way of thinking about threads. * Maybe this can help people understand asynchronous function is actually a * broader/identical view of running threads, * * class MyRunnable { * public: * void run(); * }; * * MyRunnable thread; * AsyncFunc func(&thread, &MyRunnable::run); * thread.run(); * * Well, asynchronous function is sometimes more flexible in writing a server, * because it can bind different threads to methods on the same object: * * class MyServer { * public: * void thread1(); * void thread2(); * }; * * MyServer server; * AsyncFunc func1(&server, &MyServer::thread1); * AsyncFunc func2(&server, &MyServer::thread2); * func1.start(); * func2.start(); * ...now both threads are running, accessing the same server object. * * There is nothing wrong embedding the async function object itself in the * class like this, * * class MyServer { * public: * MyServer() * : m_thread1(this, &MyServer::thread1), * : m_thread2(this, &MyServer::thread2) { * } * * void thread1(); * void thread2(); * * void start() { * m_thread1.start(); * m_thread2.start(); * } * * private: * AsyncFunc m_thread1; * AsyncFunc m_thread2; * }; * */ class AsyncFuncImpl { public: typedef void PFN_THREAD_FUNC(void *); /** * The global static to feed into pthread_create(), and this will delegate * the work to AsyncFuncImpl::threadFuncImpl(). */ static void *ThreadFunc(void *obj); /** * Called by AsyncFunc so we can call func(obj) back on thread running. */ AsyncFuncImpl(void *obj, PFN_THREAD_FUNC *func); ~AsyncFuncImpl(); /** * Starts this thread. */ void start(); /** * Waits until this thread finishes running. */ bool waitForEnd(int seconds = 0); /** * Starts and waits until this thread finishes running. */ void run() { start(); waitForEnd(); } pthread_attr_t *getThreadAttr() { return &m_attr; } static void SetThreadInitFunc(PFN_THREAD_FUNC* func, void *arg) { s_initFunc = func; s_initFuncArg = arg; } static void SetThreadFiniFunc(PFN_THREAD_FUNC* func, void *arg) { s_finiFunc = func; s_finiFuncArg = arg; } static PFN_THREAD_FUNC* GetThreadInitFunc() { return s_initFunc; } static PFN_THREAD_FUNC* GetThreadFiniFunc() { return s_finiFunc; } void setNoInit() { m_noInit = true; } private: Synchronizable m_stopMonitor; void* m_obj; PFN_THREAD_FUNC* m_func; static PFN_THREAD_FUNC* s_initFunc; static PFN_THREAD_FUNC* s_finiFunc; static void* s_initFuncArg; static void* s_finiFuncArg; void* m_threadStack; size_t m_stackSize; pthread_attr_t m_attr; pthread_t m_threadId; Exception* m_exception; // exception was thrown and thread was terminated bool m_stopped; bool m_noInit; static const size_t m_stackSizeMinimum = 8388608; // 8MB /** * Called by ThreadFunc() to delegate the work. */ void threadFuncImpl(); }; /////////////////////////////////////////////////////////////////////////////// /** * We could have written AysncFunc directly with those methods implemented * inside AsyncFuncImpl class, but this way we reduce sizes of our code by * only templatizing a very minimal piece of code, sharing everything inside * AsyncFuncImpl by all AsyncFunc classes. */ template class AsyncFunc : public AsyncFuncImpl { public: AsyncFunc(T *obj, void (T::*member_func)()) : AsyncFuncImpl((void*)this, run_), m_obj(obj), m_memberFunc(member_func) { } static void run_(void *obj) { AsyncFunc *p = (AsyncFunc*)obj; (p->m_obj->*(p->m_memberFunc))(); } private: T *m_obj; void (T::*m_memberFunc)(); }; /////////////////////////////////////////////////////////////////////////////// } #endif // __CONCURRENCY_ASYNC_FUNC_H__