llpumpio.h
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:14k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llpumpio.h
  3.  * @author Phoenix
  4.  * @date 2004-11-19
  5.  * @brief Declaration of pump class which manages io chains.
  6.  *
  7.  * $LicenseInfo:firstyear=2004&license=viewergpl$
  8.  * 
  9.  * Copyright (c) 2004-2010, Linden Research, Inc.
  10.  * 
  11.  * Second Life Viewer Source Code
  12.  * The source code in this file ("Source Code") is provided by Linden Lab
  13.  * to you under the terms of the GNU General Public License, version 2.0
  14.  * ("GPL"), unless you have obtained a separate licensing agreement
  15.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  16.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  17.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  18.  * 
  19.  * There are special exceptions to the terms and conditions of the GPL as
  20.  * it is applied to this Source Code. View the full text of the exception
  21.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  22.  * online at
  23.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  24.  * 
  25.  * By copying, modifying or distributing this software, you acknowledge
  26.  * that you have read and understood your obligations described above,
  27.  * and agree to abide by those obligations.
  28.  * 
  29.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  30.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  31.  * COMPLETENESS OR PERFORMANCE.
  32.  * $/LicenseInfo$
  33.  */
  34. #ifndef LL_LLPUMPIO_H
  35. #define LL_LLPUMPIO_H
  36. #include <set>
  37. #if LL_LINUX  // needed for PATH_MAX in APR.
  38. #include <sys/param.h>
  39. #endif
  40. #include "apr_pools.h"
  41. #include "llbuffer.h"
  42. #include "llframetimer.h"
  43. #include "lliopipe.h"
  44. #include "llrun.h"
  45. // Define this to enable use with the APR thread library.
  46. //#define LL_THREADS_APR 1
  47. // some simple constants to help with timeouts
  48. extern const F32 DEFAULT_CHAIN_EXPIRY_SECS;
  49. extern const F32 SHORT_CHAIN_EXPIRY_SECS;
  50. extern const F32 NEVER_CHAIN_EXPIRY_SECS;
  51. /** 
  52.  * @class LLPumpIO
  53.  * @brief Class to manage sets of io chains.
  54.  *
  55.  * The pump class provides a thread abstraction for doing IO based
  56.  * communication between two threads in a structured and optimized for
  57.  * processor time. The primary usage is to create a pump, and call
  58.  * <code>pump()</code> on a thread used for IO and call
  59.  * <code>respond()</code> on a thread that is expected to do higher
  60.  * level processing. You can call almost any other method from any
  61.  * thread - see notes for each method for details. In order for the
  62.  * threading abstraction to work, you need to call <code>prime()</code>
  63.  * with a valid apr pool.
  64.  * A pump instance manages much of the state for the pipe, including
  65.  * the list of pipes in the chain, the channel for each element in the
  66.  * chain, the buffer, and if any pipe has marked the stream or process
  67.  * as done. Pipes can also set file descriptor based conditional
  68.  * statements so that calls to process do not happen until data is
  69.  * ready to be read or written.  Pipes control execution of calls to
  70.  * process by returning a status code such as STATUS_OK or
  71.  * STATUS_BREAK.
  72.  * One way to conceptualize the way IO will work is that a pump
  73.  * combines the unit processing of pipes to behave like file pipes on
  74.  * the unix command line.
  75.  */
  76. class LLPumpIO
  77. {
  78. public:
  79. /**
  80.  * @brief Constructor.
  81.  */
  82. LLPumpIO(apr_pool_t* pool);
  83. /**
  84.  * @brief Destructor.
  85.  */
  86. ~LLPumpIO();
  87. /**
  88.  * @brief Prepare this pump for usage.
  89.  *
  90.  * If you fail to call this method prior to use, the pump will
  91.  * try to work, but will not come with any thread locking
  92.  * mechanisms.
  93.  * @param pool The apr pool to use.
  94.  * @return Returns true if the pump is primed.
  95.  */
  96. bool prime(apr_pool_t* pool);
  97. /**
  98.  * @brief Typedef for having a chain of pipes.
  99.  */
  100. typedef std::vector<LLIOPipe::ptr_t> chain_t;
  101. /** 
  102.  * @brief Add a chain to this pump and process in the next cycle.
  103.  *
  104.  * This method will automatically generate a buffer and assign
  105.  * each link in the chain as if it were the consumer to the
  106.  * previous.
  107.  * @param chain The pipes for the chain
  108.  * @param timeout The number of seconds in the future to
  109.  * expire. Pass in 0.0f to never expire.
  110.  * @return Returns true if anything was added to the pump.
  111.  */
  112. bool addChain(const chain_t& chain, F32 timeout);
  113. /** 
  114.  * @brief Struct to associate a pipe with it's buffer io indexes.
  115.  */
  116. struct LLLinkInfo
  117. {
  118. LLIOPipe::ptr_t mPipe;
  119. LLChannelDescriptors mChannels;
  120. };
  121. /** 
  122.  * @brief Typedef for having a chain of <code>LLLinkInfo</code>
  123.  * instances.
  124.  */
  125. typedef std::vector<LLLinkInfo> links_t;
  126. /** 
  127.  * @brief Add a chain to this pump and process in the next cycle.
  128.  *
  129.  * This method provides a slightly more sophisticated method for
  130.  * adding a chain where the caller can specify which link elements
  131.  * are on what channels. This method will fail if no buffer is
  132.  * provided since any calls to generate new channels for the
  133.  * buffers will cause unpredictable interleaving of data.
  134.  * @param links The pipes and io indexes for the chain
  135.  * @param data Shared pointer to data buffer
  136.  * @param context Potentially undefined context meta-data for chain.
  137.  * @param timeout The number of seconds in the future to
  138.  * expire. Pass in 0.0f to never expire.
  139.  * @return Returns true if anything was added to the pump.
  140.  */
  141. bool addChain(
  142. const links_t& links,
  143. LLIOPipe::buffer_ptr_t data,
  144. LLSD context,
  145. F32 timeout);
  146. /** 
  147.  * @brief Set or clear a timeout for the running chain
  148.  *
  149.  * @param timeout The number of seconds in the future to
  150.  * expire. Pass in 0.0f to never expire.
  151.  * @return Returns true if the timer was set.
  152.  */
  153. bool setTimeoutSeconds(F32 timeout);
  154. /** 
  155.  * @brief Adjust the timeout of the running chain.
  156.  *
  157.  * This method has no effect if there is no timeout on the chain.
  158.  * @param delta The number of seconds to add to/remove from the timeout.
  159.  */
  160. void adjustTimeoutSeconds(F32 delta);
  161. /** 
  162.  * @brief Set up file descriptors for for the running chain.
  163.  * @see rebuildPollset()
  164.  *
  165.  * There is currently a limit of one conditional per pipe.
  166.  * *NOTE: The internal mechanism for building a pollset based on
  167.  * pipe/pollfd/chain generates an epoll error on linux (and
  168.  * probably behaves similarly on other platforms) because the
  169.  * pollset rebuilder will add each apr_pollfd_t serially. This
  170.  * does not matter for pipes on the same chain, since any
  171.  * signalled pipe will eventually invoke a call to process(), but
  172.  * is a problem if the same apr_pollfd_t is on different
  173.  * chains. Once we have more than just network i/o on the pump,
  174.  * this might matter.
  175.  * *FIX: Given the structure of the pump and pipe relationship,
  176.  * this should probably go through a different mechanism than the
  177.  * pump. I think it would be best if the pipe had some kind of
  178.  * controller which was passed into <code>process()</code> rather
  179.  * than the pump which exposed this interface.
  180.  * @param pipe The pipe which is setting a conditional
  181.  * @param poll The entire socket and read/write condition - null to remove
  182.  * @return Returns true if the poll state was set.
  183.  */
  184. bool setConditional(LLIOPipe* pipe, const apr_pollfd_t* poll);
  185. /** 
  186.  * @brief Lock the current chain.
  187.  * @see sleepChain() since it relies on the implementation of this method.
  188.  *
  189.  * This locks the currently running chain so that no more calls to
  190.  * <code>process()</code> until you call <code>clearLock()</code>
  191.  * with the lock identifier.
  192.  * *FIX: Given the structure of the pump and pipe relationship,
  193.  * this should probably go through a different mechanism than the
  194.  * pump. I think it would be best if the pipe had some kind of
  195.  * controller which was passed into <code>process()</code> rather
  196.  * than the pump which exposed this interface.
  197.  * @return Returns the lock identifer to be used in
  198.  * <code>clearLock()</code> or 0 on failure.
  199.  */
  200. S32 setLock();
  201. /** 
  202.  * @brief Clears the identified lock.
  203.  *
  204.  * @param links A container for the links which will be appended
  205.  */
  206. void clearLock(S32 key);
  207. /**
  208.  * @brief Stop processing a chain for a while.
  209.  * @see setLock()
  210.  *
  211.  * This method will <em>not</em> update the timeout for this
  212.  * chain, so it is possible to sleep the chain until it is
  213.  * collected by the pump during a timeout cleanup.
  214.  * @param seconds The number of seconds in the future to
  215.  * resume processing.
  216.  * @return Returns true if the 
  217.  */
  218. bool sleepChain(F64 seconds);
  219. /** 
  220.  * @brief Copy the currently running chain link info
  221.  *
  222.  * *FIX: Given the structure of the pump and pipe relationship,
  223.  * this should probably go through a different mechanism than the
  224.  * pump. I think it would be best if the pipe had some kind of
  225.  * controller which was passed into <code>process()</code> rather
  226.  * than the pump which exposed this interface.
  227.  * @param links A container for the links which will be appended
  228.  * @return Returns true if the currently running chain was copied.
  229.  */
  230. bool copyCurrentLinkInfo(links_t& links) const;
  231. /** 
  232.  * @brief Call this method to call process on all running chains.
  233.  *
  234.  * This method iterates through the running chains, and if all
  235.  * pipe on a chain are unconditionally ready or if any pipe has
  236.  * any conditional processiong condition then process will be
  237.  * called on every chain which has requested processing.  that
  238.  * chain has a file descriptor ready, <code>process()</code> will
  239.  * be called for all pipes which have requested it.
  240.  */
  241. void pump(const S32& poll_timeout);
  242. void pump();
  243. /** 
  244.  * @brief Add a chain to a special queue which will be called
  245.  * during the next call to <code>callback()</code> and then
  246.  * dropped from the queue.
  247.  *
  248.  * @param chain The IO chain that will get one <code>process()</code>.
  249.  */
  250. //void respond(const chain_t& pipes);
  251. /** 
  252.  * @brief Add pipe to a special queue which will be called
  253.  * during the next call to <code>callback()</code> and then dropped
  254.  * from the queue.
  255.  *
  256.  * This call will add a single pipe, with no buffer, context, or
  257.  * channel information to the callback queue. It will be called
  258.  * once, and then dropped.
  259.  * @param pipe A single io pipe which will be called
  260.  * @return Returns true if anything was added to the pump.
  261.  */
  262. bool respond(LLIOPipe* pipe);
  263. /** 
  264.  * @brief Add a chain to a special queue which will be called
  265.  * during the next call to <code>callback()</code> and then
  266.  * dropped from the queue.
  267.  *
  268.  * It is important to remember that you should not add a data
  269.  * buffer or context which may still be in another chain - that
  270.  * will almost certainly lead to a problems. Ensure that you are
  271.  * done reading and writing to those parameters, have new
  272.  * generated, or empty pointers. 
  273.  * @param links The pipes and io indexes for the chain
  274.  * @param data Shared pointer to data buffer
  275.  * @param context Potentially undefined context meta-data for chain.
  276.  * @return Returns true if anything was added to the pump.
  277.  */
  278. bool respond(
  279. const links_t& links,
  280. LLIOPipe::buffer_ptr_t data,
  281. LLSD context);
  282. /** 
  283.  * @brief Run through the callback queue and call <code>process()</code>.
  284.  *
  285.  * This call will process all prending responses and call process
  286.  * on each. This method will then drop all processed callback
  287.  * requests which may lead to deleting the referenced objects.
  288.  */
  289. void callback();
  290. /** 
  291.  * @brief Enumeration to send commands to the pump.
  292.  */
  293. enum EControl
  294. {
  295. PAUSE,
  296. RESUME,
  297. };
  298. /** 
  299.  * @brief Send a command to the pump.
  300.  *
  301.  * @param op What control to send to the pump.
  302.  */
  303. void control(EControl op);
  304. protected:
  305. /** 
  306.  * @brief State of the pump
  307.  */
  308. enum EState
  309. {
  310. NORMAL,
  311. PAUSING,
  312. PAUSED
  313. };
  314. // instance data
  315. EState mState;
  316. bool mRebuildPollset;
  317. apr_pollset_t* mPollset;
  318. S32 mPollsetClientID;
  319. S32 mNextLock;
  320. std::set<S32> mClearLocks;
  321. // This is the pump's runnable scheduler used for handling
  322. // expiring locks.
  323. LLRunner mRunner;
  324. // This structure is the stuff we track while running chains.
  325. struct LLChainInfo
  326. {
  327. // methods
  328. LLChainInfo();
  329. void setTimeoutSeconds(F32 timeout);
  330. void adjustTimeoutSeconds(F32 delta);
  331. // basic member data
  332. bool mInit;
  333. S32 mLock;
  334. LLFrameTimer mTimer;
  335. links_t::iterator mHead;
  336. links_t mChainLinks;
  337. LLIOPipe::buffer_ptr_t mData;
  338. bool mEOS;
  339. LLSD mContext;
  340. // tracking inside the pump
  341. typedef std::pair<LLIOPipe::ptr_t, apr_pollfd_t> pipe_conditional_t;
  342. typedef std::vector<pipe_conditional_t> conditionals_t;
  343. conditionals_t mDescriptors;
  344. };
  345. // All the running chains & info
  346.   typedef std::vector<LLChainInfo> pending_chains_t;
  347. pending_chains_t mPendingChains;
  348. typedef std::list<LLChainInfo> running_chains_t;
  349. running_chains_t mRunningChains;
  350. typedef running_chains_t::iterator current_chain_t;
  351. current_chain_t mCurrentChain;
  352. // structures necessary for doing callbacks
  353. // since the callbacks only get one chance to run, we do not have
  354. // to maintain a list.
  355. typedef std::vector<LLChainInfo> callbacks_t;
  356. callbacks_t mPendingCallbacks;
  357. callbacks_t mCallbacks;
  358. // memory allocator for pollsets & mutexes.
  359. apr_pool_t* mPool;
  360. apr_pool_t* mCurrentPool;
  361. S32 mCurrentPoolReallocCount;
  362. #if LL_THREADS_APR
  363. apr_thread_mutex_t* mChainsMutex;
  364. apr_thread_mutex_t* mCallbackMutex;
  365. #else
  366. int* mChainsMutex;
  367. int* mCallbackMutex;
  368. #endif
  369. protected:
  370. void initialize(apr_pool_t* pool);
  371. void cleanup();
  372. /** 
  373.  * @brief Given the internal state of the chains, rebuild the pollset
  374.  * @see setConditional()
  375.  */
  376. void rebuildPollset();
  377. /** 
  378.  * @brief Process the chain passed in.
  379.  *
  380.  * This method will potentially modify the internals of the
  381.  * chain. On end, the chain.mHead will equal
  382.  * chain.mChainLinks.end().
  383.  * @param chain The LLChainInfo object to work on.
  384.  */
  385. void processChain(LLChainInfo& chain);
  386. /** 
  387.  * @brief Rewind through the chain to try to recover from an error.
  388.  *
  389.  * This method will potentially modify the internals of the
  390.  * chain.
  391.  * @param chain The LLChainInfo object to work on.
  392.  * @return Retuns true if someone handled the error
  393.  */
  394. bool handleChainError(LLChainInfo& chain, LLIOPipe::EStatus error);
  395. public:
  396. /** 
  397.  * @brief Return number of running chains.
  398.  *
  399.  * *NOTE: This is only used in debugging and not considered
  400.  * efficient or safe enough for production use.
  401.  */
  402. running_chains_t::size_type runningChains() const
  403. {
  404. return mRunningChains.size();
  405. }
  406. };
  407. #endif // LL_LLPUMPIO_H