llbuffer.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. /**
  2. * @file llbuffer.h
  3. * @author Phoenix
  4. * @date 2005-09-20
  5. * @brief Declaration of buffer and buffer arrays primarily used in I/O.
  6. *
  7. * $LicenseInfo:firstyear=2005&license=viewergpl$
  8. *
  9. * Copyright (c) 2005-2009, 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_LLBUFFER_H
  35. #define LL_LLBUFFER_H
  36. /**
  37. * Declaration of classes used for minimizing calls to new[], memcpy() and
  38. * delete[]. Typically, you would create an LLBufferArray, feed it data, modify
  39. * and add segments as you process it, and feed it to a sink.
  40. */
  41. #include <list>
  42. #include <vector>
  43. #include "llpreprocessor.h"
  44. #include "llthread.h"
  45. /**
  46. * @class LLChannelDescriptors
  47. * @brief A way simple interface to accesss channels inside a buffer
  48. */
  49. class LLChannelDescriptors
  50. {
  51. public:
  52. // enumeration for segmenting the channel information
  53. enum { E_CHANNEL_COUNT = 3 };
  54. LLChannelDescriptors()
  55. : mBaseChannel(0)
  56. {
  57. }
  58. explicit LLChannelDescriptors(S32 base)
  59. : mBaseChannel(base)
  60. {
  61. }
  62. LL_INLINE S32 in() const { return mBaseChannel; }
  63. LL_INLINE S32 out() const { return mBaseChannel + 1; }
  64. #if 0
  65. LL_INLINE S32 err() const { return mBaseChannel + 2; }
  66. #endif
  67. protected:
  68. S32 mBaseChannel;
  69. };
  70. /**
  71. * @class LLSegment
  72. * @brief A segment is a single, contiguous chunk of memory in a buffer
  73. *
  74. * Each segment represents a contiguous addressable piece of memory which is
  75. * located inside a buffer. The segment is not responsible for allocation or
  76. * deallcoation of the data. Each segment is a light weight object, and simple
  77. * enough to copy around, use, and generate as necessary. This is the preferred
  78. * interface for working with memory blocks, since it is the only way to
  79. * safely, inexpensively, and directly access linear blocks of memory.
  80. */
  81. class LLSegment
  82. {
  83. public:
  84. LLSegment()
  85. : mChannel(0),
  86. mData(NULL),
  87. mSize(0)
  88. {
  89. }
  90. LLSegment(S32 channel, U8* data, S32 data_len)
  91. : mChannel(channel),
  92. mData(data),
  93. mSize(data_len)
  94. {
  95. }
  96. ~LLSegment() {}
  97. /**
  98. * @brief Check if this segment is on the given channel.
  99. *
  100. */
  101. LL_INLINE bool isOnChannel(S32 channel) const { return mChannel == channel; }
  102. /**
  103. * @brief Get the channel
  104. */
  105. LL_INLINE S32 getChannel() const { return mChannel; }
  106. /**
  107. * @brief Set the channel
  108. */
  109. LL_INLINE void setChannel(S32 channel) { mChannel = channel; }
  110. /**
  111. * @brief Return a raw pointer to the current data set.
  112. *
  113. * The pointer returned can be used for reading or even adjustment if you
  114. * are a bit crazy up to size() bytes into memory.
  115. * @return A potentially NULL pointer to the raw buffer data
  116. */
  117. LL_INLINE U8* data() const { return mData; }
  118. /**
  119. * @brief Return the size of the segment
  120. */
  121. LL_INLINE S32 size() const { return mSize; }
  122. /**
  123. * @brief Check if two segments are the same.
  124. *
  125. * Two segments are considered equal if they are on the same channel and
  126. * cover the exact same address range.
  127. * @param rhs the segment to compare with this segment.
  128. * @return Returns true if they are equal.
  129. */
  130. LL_INLINE bool operator==(const LLSegment& rhs) const
  131. {
  132. if (mData != rhs.mData || mSize != rhs.mSize ||
  133. mChannel != rhs.mChannel)
  134. {
  135. return false;
  136. }
  137. return true;
  138. }
  139. protected:
  140. S32 mChannel;
  141. U8* mData;
  142. S32 mSize;
  143. };
  144. /**
  145. * @class LLBuffer
  146. * @brief Abstract base class for buffers
  147. *
  148. * This class declares the interface necessary for buffer arrays. A buffer is
  149. * not necessarily a single contiguous memory chunk, so please do not
  150. * circumvent the segment API.
  151. */
  152. class LLBuffer
  153. {
  154. public:
  155. /**
  156. * @brief The buffer base class should have no responsibilities
  157. * other than an interface.
  158. */
  159. virtual ~LLBuffer() {}
  160. /**
  161. * @brief Generate a segment for this buffer.
  162. *
  163. * The segment returned is always contiguous memory. This call can fail if
  164. * no contiguous memory is available, eg, offset is past the end. The
  165. * segment returned may be smaller than the requested size. The segment
  166. * will never be larger than the requested size.
  167. * @param channel The channel for the segment.
  168. * @param offset The offset from zero in the buffer.
  169. * @param size The requested size of the segment.
  170. * @param segment[out] The out-value from the operation
  171. * @return Returns true if a segment was found.
  172. */
  173. virtual bool createSegment(S32 channel, S32 size, LLSegment& segment) = 0;
  174. /**
  175. * @brief Reclaim a segment from this buffer.
  176. *
  177. * This method is called on a buffer object when a caller is done with a
  178. * contiguous segment of memory inside this buffer. Since segments can be
  179. * cut arbitrarily outside of the control of the buffer, this segment may
  180. * not match any segment returned from <code>createSegment()</code>.
  181. * @param segment The contiguous buffer segment to reclaim.
  182. * @return Returns true if the call was successful.
  183. */
  184. virtual bool reclaimSegment(const LLSegment& segment) = 0;
  185. /**
  186. * @brief Test if a segment is inside this buffer.
  187. *
  188. * @param segment The contiguous buffer segment to test.
  189. * @return Returns true if the segment is in the bufffer.
  190. */
  191. virtual bool containsSegment(const LLSegment& segment) const = 0;
  192. /**
  193. * @brief Return the current number of bytes allocated.
  194. *
  195. * This was implemented as a debugging tool, and it is not necessarily a
  196. * good idea to use it for anything else.
  197. */
  198. virtual S32 capacity() const = 0;
  199. };
  200. /**
  201. * @class LLHeapBuffer
  202. * @brief A large contiguous buffer allocated on the heap with new[].
  203. *
  204. * This class is a simple buffer implementation which allocates chunks off the
  205. * heap. Once a buffer is constructed, it's buffer has a fixed length.
  206. */
  207. class LLHeapBuffer : public LLBuffer
  208. {
  209. protected:
  210. LOG_CLASS(LLHeapBuffer);
  211. public:
  212. /**
  213. * @brief Construct a heap buffer with a reasonable default size.
  214. */
  215. LLHeapBuffer();
  216. /**
  217. * @brief Construct a heap buffer with a specified size.
  218. *
  219. * @param size The minimum size of the buffer.
  220. */
  221. explicit LLHeapBuffer(S32 size);
  222. /**
  223. * @brief Construct a heap buffer of minimum size len, and copy from src.
  224. *
  225. * @param src The source of the data to be copied.
  226. * @param len The minimum size of the buffer.
  227. */
  228. LLHeapBuffer(const U8* src, S32 len);
  229. /**
  230. * @brief Simple destruction.
  231. */
  232. virtual ~LLHeapBuffer();
  233. /**
  234. * @brief Get the number of bytes left in the buffer.
  235. *
  236. * Note that this is not a virtual function, and only available in the
  237. * LLHeapBuffer as a debugging aid.
  238. * @return Returns the number of bytes left.
  239. */
  240. S32 bytesLeft() const;
  241. /**
  242. * @brief Generate a segment for this buffer.
  243. *
  244. * The segment returned is always contiguous memory. This call can fail if
  245. * no contiguous memory is available, eg, offset is past the end. The
  246. * segment returned may be smaller than the requested size. It is up to the
  247. * caller to delete the segment returned.
  248. * @param channel The channel for the segment.
  249. * @param offset The offset from zero in the buffer
  250. * @param size The requested size of the segment
  251. * @param segment[out] The out-value from the operation
  252. * @return Returns true if a segment was found.
  253. */
  254. virtual bool createSegment(S32 channel, S32 size, LLSegment& segment);
  255. /**
  256. * @brief reclaim a segment from this buffer.
  257. *
  258. * This method is called on a buffer object when a caller is done with a
  259. * contiguous segment of memory inside this buffer. Since segments can be
  260. * cut arbitrarily outside of the control of the buffer, this segment may
  261. * not match any segment returned from <code>createSegment()</code>.
  262. * This call will fail if the segment passed in is note completely inside
  263. * the buffer, eg, if the segment starts before this buffer in memory or
  264. * ends after it.
  265. * @param segment The contiguous buffer segment to reclaim.
  266. * @return Returns true if the call was successful.
  267. */
  268. virtual bool reclaimSegment(const LLSegment& segment);
  269. /**
  270. * @brief Test if a segment is inside this buffer.
  271. *
  272. * @param segment The contiguous buffer segment to test.
  273. * @return Returns true if the segment is in the bufffer.
  274. */
  275. virtual bool containsSegment(const LLSegment& segment) const;
  276. /**
  277. * @brief Return the current number of bytes allocated.
  278. */
  279. LL_INLINE virtual S32 capacity() const { return mSize; }
  280. protected:
  281. U8* mBuffer;
  282. S32 mSize;
  283. U8* mNextFree;
  284. S32 mReclaimedBytes;
  285. private:
  286. /**
  287. * @brief Helper method to allocate a buffer and correctly set intertnal
  288. * state of this buffer.
  289. */
  290. void allocate(S32 size);
  291. };
  292. /**
  293. * @class LLBufferArray
  294. * @brief Class to represent scattered memory buffers and in-order segments of
  295. * that buffered data.
  296. *
  297. * *NOTE: This class needs to have an iovec interface
  298. */
  299. class LLBufferArray
  300. {
  301. public:
  302. typedef std::vector<LLBuffer*> buffer_list_t;
  303. typedef buffer_list_t::iterator buffer_iterator_t;
  304. typedef buffer_list_t::const_iterator const_buffer_iterator_t;
  305. typedef std::list<LLSegment> segment_list_t;
  306. typedef segment_list_t::const_iterator const_segment_iterator_t;
  307. typedef segment_list_t::iterator segment_iterator_t;
  308. enum { npos = 0xffffffff };
  309. LLBufferArray();
  310. ~LLBufferArray();
  311. /* @name Channel methods
  312. */
  313. //@{
  314. /**
  315. * @brief Generate the a channel descriptor which consumes the output for
  316. * the channel passed in.
  317. */
  318. static LLChannelDescriptors makeChannelConsumer(const LLChannelDescriptors& channels);
  319. /**
  320. * @brief Generate the next channel descriptor for this buffer array.
  321. *
  322. * The channel descriptor interface is how the buffer array clients can
  323. * know where to read and write data. Use this interface to get the 'next'
  324. * channel set for usage. This is a bit of a simple hack until it's utility
  325. * indicates it should be extended.
  326. * @return Returns a valid channel descriptor set for input and output.
  327. */
  328. LLChannelDescriptors nextChannel();
  329. //@}
  330. /* @name Data methods
  331. */
  332. //@{
  333. /**
  334. * @brief Return the sum of all allocated bytes.
  335. */
  336. S32 capacity() const;
  337. #if 0 // These methods will be useful once there is any kind of buffer
  338. // besides a heap buffer.
  339. bool append(EBufferChannel channel, LLBuffer* data);
  340. bool prepend(EBufferChannel channel, LLBuffer* data);
  341. bool insertAfter(segment_iterator_t segment, EBufferChannel channel,
  342. LLBuffer* data);
  343. #endif
  344. /**
  345. * @brief Put data on a channel at the end of this buffer array.
  346. *
  347. * The data is copied from src into the buffer array. At least one new
  348. * segment is created and put on the end of the array. This object will
  349. * internally allocate new buffers if necessary.
  350. * @param channel The channel for this data
  351. * @param src The start of memory for the data to be copied
  352. * @param len The number of bytes of data to copy
  353. * @return Returns true if the method worked.
  354. */
  355. bool append(S32 channel, const U8* src, S32 len);
  356. /**
  357. * @brief Put data on a channel at the front of this buffer array.
  358. *
  359. * The data is copied from src into the buffer array. At least one new
  360. * segment is created and put in the front of the array. This object will
  361. * internally allocate new buffers if necessary.
  362. * @param channel The channel for this data
  363. * @param src The start of memory for the data to be copied
  364. * @param len The number of bytes of data to copy
  365. * @return Returns true if the method worked.
  366. */
  367. bool prepend(S32 channel, const U8* src, S32 len);
  368. /**
  369. * @brief Insert data into a buffer array after a particular segment.
  370. *
  371. * The data is copied from src into the buffer array. At least one new
  372. * segment is created and put in the array. This object will internally
  373. * allocate new buffers if necessary.
  374. * @param segment The segment in front of the new segments location
  375. * @param channel The channel for this data
  376. * @param src The start of memory for the data to be copied
  377. * @param len The number of bytes of data to copy
  378. * @return Returns true if the method worked.
  379. */
  380. bool insertAfter(segment_iterator_t segment, S32 channel, const U8* src,
  381. S32 len);
  382. /**
  383. * @brief Count bytes in the buffer array on the specified channel
  384. *
  385. * @param channel The channel to count.
  386. * @param start The start address in the array for counting. You can
  387. * specify NULL to start at the beginning.
  388. * @return Returns the number of bytes in the channel after start
  389. */
  390. S32 countAfter(S32 channel, U8* start) const;
  391. /**
  392. * @brief Count all bytes on channel.
  393. *
  394. * Helper method which just calls countAfter().
  395. * @param channel The channel to count.
  396. * @return Returns the number of bytes in the channel.
  397. */
  398. LL_INLINE S32 count(S32 channel) const { return countAfter(channel, NULL); }
  399. /**
  400. * @brief Read bytes in the buffer array on the specified channel
  401. *
  402. * You should prefer iterating over segments is possible since this method
  403. * requires you to allocate large buffers - precisely what this class is
  404. * trying to prevent. This method will skip any segments which are not on
  405. * the given channel, so this method would usually be used to read a
  406. * channel and copy that to a log or a socket buffer or something.
  407. * @param channel The channel to read.
  408. * @param start The start address in the array for reading. You can specify
  409. * NULL to start at the beginning.
  410. * @param dest The destination of the data read. This must be at least len
  411. * bytes long.
  412. * @param len[in,out] <b>in</b> How many bytes to read. <b>out</b> How many
  413. * bytes were read.
  414. * @return Returns the address of the last read byte.
  415. */
  416. U8* readAfter(S32 channel, U8* start, U8* dest, S32& len) const;
  417. /**
  418. * @brief Find an address in a buffer array
  419. *
  420. * @param channel The channel to seek in.
  421. * @param start The start address in the array for the seek operation. You
  422. * can specify NULL to start the seek at the beginning, or pass in npos to
  423. * start at the end.
  424. * @param delta How many bytes to seek through the array.
  425. * @return Returns the address of the last read byte.
  426. */
  427. U8* seek(S32 channel, U8* start, S32 delta) const;
  428. //@}
  429. /* @name Buffer interaction
  430. */
  431. //@{
  432. /**
  433. * @brief Take the contents of another buffer array
  434. *
  435. * This method simply strips the contents out of the source buffery array -
  436. * segments, buffers, etc, and appends them to this instance. After this
  437. * operation, the source is empty and ready for reuse.
  438. * @param source The source buffer
  439. * @return Returns true if the operation succeeded.
  440. */
  441. bool takeContents(LLBufferArray& source);
  442. //@}
  443. /* @name Segment methods
  444. */
  445. //@{
  446. /**
  447. * @brief Split a segments so that address is the last address of one
  448. * segment, and the rest of the original segment becomes another segment on
  449. * the same channel.
  450. *
  451. * After this method call,
  452. * <code>getLastSegmentAddress(*getSegment(address)) == address</code>
  453. * should be true. This call will only create a new segment if the
  454. * statement above is false before the call. Since you usually call
  455. * splitAfter() to change a segment property, use getSegment() to perform
  456. * those operations.
  457. * @param address The address which will become the last address of the
  458. * segment it is in.
  459. * @return Returns an iterator to the segment which contains
  460. * <code>address</code> which is <code>endSegment()</code> on failure.
  461. */
  462. segment_iterator_t splitAfter(U8* address);
  463. /**
  464. * @brief Get the first segment in the buffer array.
  465. *
  466. * @return Returns the segment if there is one.
  467. */
  468. segment_iterator_t beginSegment();
  469. /**
  470. * @brief Get the one-past-the-end segment in the buffer array
  471. *
  472. * @return Returns the iterator for an invalid segment location.
  473. */
  474. segment_iterator_t endSegment();
  475. /**
  476. * @brief Get the segment which holds the given address.
  477. *
  478. * As opposed to some methods, passing a NULL will result in returning the
  479. * end segment.
  480. * @param address An address in the middle of the sought segment.
  481. * @return Returns the iterator for the segment or endSegment() on failure.
  482. */
  483. const_segment_iterator_t getSegment(U8* address) const;
  484. /**
  485. * @brief Get the segment which holds the given address.
  486. *
  487. * As opposed to some methods, passing a NULL will result in returning the
  488. * end segment.
  489. * @param address An address in the middle of the sought segment.
  490. * @return Returns the iterator for the segment or endSegment() on failure.
  491. */
  492. segment_iterator_t getSegment(U8* address);
  493. /**
  494. * @brief Get a segment iterator after address, and a constructed segment
  495. * to represent the next linear block of memory.
  496. *
  497. * This method is a helper by giving you the largest segment possible in
  498. * the out-value param after the address provided. The iterator will be
  499. * useful for iteration, while the segment can be used for direct access to
  500. * memory after address if the return values isnot end. Passing in NULL
  501. * will return beginSegment() which may be endSegment(). The segment
  502. * returned will only be zero length if the return value equals end. This
  503. * is really just a helper method, since all the information returned could
  504. * be constructed through other methods.
  505. * @param address An address in the middle of the sought segment.
  506. * @param segment[out] segment to be used for reading or writing
  507. * @return Returns an iterator which contains at least segment or
  508. * endSegment() on failure.
  509. */
  510. segment_iterator_t constructSegmentAfter(U8* address, LLSegment& segment);
  511. /**
  512. * @brief Make a new segment at the end of buffer array
  513. *
  514. * This method will attempt to create a new and empty segment of the
  515. * specified length. The segment created may be shorter than requested.
  516. * @param channel[in] The channel for the newly created segment.
  517. * @param length[in] The requested length of the segment.
  518. * @return Returns an iterator which contains at least segment or
  519. * endSegment() on failure.
  520. */
  521. segment_iterator_t makeSegment(S32 channel, S32 length);
  522. /**
  523. * @brief Erase the segment if it is in the buffer array.
  524. *
  525. * @param iter An iterator referring to the segment to erase.
  526. * @return Returns true on success.
  527. */
  528. bool eraseSegment(const segment_iterator_t& iter);
  529. /**
  530. * @brief Lock the mutex if it exists
  531. * This method locks mMutexp to make accessing LLBufferArray thread-safe
  532. */
  533. LL_INLINE void lock() { if (mMutexp) mMutexp->lock(); }
  534. /**
  535. * @brief Unlock the mutex if it exists
  536. */
  537. LL_INLINE void unlock() { if (mMutexp) mMutexp->unlock(); }
  538. /**
  539. * @brief Return mMutexp
  540. */
  541. LL_INLINE LLMutex* getMutex() { return mMutexp; }
  542. /**
  543. * @brief Set LLBufferArray to be shared across threads or not
  544. * This method is to create mMutexp if is threaded.
  545. * @param threaded Indicates this LLBufferArray instance is shared across
  546. * threads if true.
  547. */
  548. void setThreaded(bool threaded);
  549. //@}
  550. protected:
  551. /**
  552. * @brief Optimally put data in buffers, and reutrn segments.
  553. *
  554. * This is an internal function used to create buffers as
  555. * necessary, and sequence the segments appropriately for the
  556. * various ways to copy data from src into this.
  557. * If this method fails, it may actually leak some space inside
  558. * buffers, but I am not too worried about the slim possibility
  559. * that we may have some 'dead' space which will be recovered when
  560. * the buffer (which we will not lose) is deleted. Addressing this
  561. * weakness will make the buffers almost as complex as a general
  562. * memory management system.
  563. * @param channel The channel for this data
  564. * @param src The start of memory for the data to be copied
  565. * @param len The number of bytes of data to copy
  566. * @param segments Out-value for the segments created.
  567. * @return Returns true if the method worked.
  568. */
  569. bool copyIntoBuffers(S32 channel, const U8* src, S32 len,
  570. std::vector<LLSegment>& segments);
  571. protected:
  572. S32 mNextBaseChannel;
  573. buffer_list_t mBuffers;
  574. segment_list_t mSegments;
  575. LLMutex* mMutexp;
  576. };
  577. #endif // LL_LLBUFFER_H