PageRenderTime 41ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llmessage/llpumpio.h

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