llbufferstream.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. /**
  2. * @file llbufferstream.cpp
  3. * @author Phoenix
  4. * @date 2005-10-10
  5. * @brief Implementation of the buffer iostream classes
  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. #include "linden_common.h"
  35. #include "llbufferstream.h"
  36. #include "llbuffer.h"
  37. #include "llthread.h"
  38. constexpr S32 DEFAULT_OUTPUT_SEGMENT_SIZE = 1024 * 4;
  39. /*
  40. * LLBufferStreamBuf
  41. */
  42. LLBufferStreamBuf::LLBufferStreamBuf(const LLChannelDescriptors& channels,
  43. LLBufferArray* buffer)
  44. : mChannels(channels),
  45. mBuffer(buffer)
  46. {
  47. }
  48. LLBufferStreamBuf::~LLBufferStreamBuf()
  49. {
  50. sync();
  51. }
  52. // virtual
  53. int LLBufferStreamBuf::underflow()
  54. {
  55. if (!mBuffer)
  56. {
  57. return EOF;
  58. }
  59. LLMutexLock lock(mBuffer->getMutex());
  60. LLBufferArray::segment_iterator_t iter;
  61. LLBufferArray::segment_iterator_t end = mBuffer->endSegment();
  62. U8* last_pos = (U8*)gptr();
  63. LLSegment segment;
  64. if (last_pos)
  65. {
  66. // Back up into a piece of memory we know that we have
  67. // allocated so that calls for the next segment based on
  68. // 'after' will succeed.
  69. --last_pos;
  70. iter = mBuffer->splitAfter(last_pos);
  71. if (iter != end)
  72. {
  73. // We need to clear the read segment just in case we have an early
  74. // exit in the function and never collect the next segment. Calling
  75. // eraseSegment() with the same segment twice is just like double
  76. // deleting: nothing good comes from it.
  77. mBuffer->eraseSegment(iter++);
  78. if (iter != end)
  79. {
  80. segment = *iter;
  81. }
  82. }
  83. else
  84. {
  85. // This should never really happen, but somehow, the istream is
  86. // telling the buf that it just finished reading memory that is not
  87. // in the buf. I think this would only happen if there were a bug
  88. // in the C++ stream class. Just bail.
  89. // *TODO: can we set the fail bit on the stream somehow ?
  90. return EOF;
  91. }
  92. }
  93. else
  94. {
  95. // Get iterator to full segment containing last_pos and construct
  96. // sub-segment starting at last_pos. Note: segment may != *iter at this
  97. // point.
  98. iter = mBuffer->constructSegmentAfter(last_pos, segment);
  99. }
  100. if (iter == end)
  101. {
  102. return EOF;
  103. }
  104. // Iterate through segments to find a non-empty segment on input channel.
  105. while (segment.size() == 0 || !segment.isOnChannel(mChannels.in()))
  106. {
  107. ++iter;
  108. if (iter == end)
  109. {
  110. return EOF;
  111. }
  112. segment = *(iter);
  113. }
  114. // Set up the stream to read from the next segment.
  115. char* start = (char*)segment.data();
  116. setg(start, start, start + segment.size());
  117. return *gptr();
  118. }
  119. // virtual
  120. int LLBufferStreamBuf::overflow(int c)
  121. {
  122. if (!mBuffer)
  123. {
  124. return EOF;
  125. }
  126. if (EOF == c)
  127. {
  128. // If someone puts an EOF, I suppose we should sync and return
  129. // success.
  130. if (sync() == 0)
  131. {
  132. return 1;
  133. }
  134. else
  135. {
  136. return EOF;
  137. }
  138. }
  139. // Since we got here, we have a buffer and a character to put on it
  140. LLMutexLock lock(mBuffer->getMutex());
  141. LLBufferArray::segment_iterator_t it =
  142. mBuffer->makeSegment(mChannels.out(), DEFAULT_OUTPUT_SEGMENT_SIZE);
  143. if (it != mBuffer->endSegment())
  144. {
  145. char* start = (char*)(*it).data();
  146. (*start) = (char)(c);
  147. setp(start + 1, start + (*it).size());
  148. return c;
  149. }
  150. else
  151. {
  152. return EOF;
  153. }
  154. }
  155. // virtual
  156. int LLBufferStreamBuf::sync()
  157. {
  158. int return_value = -1;
  159. if (!mBuffer)
  160. {
  161. return return_value;
  162. }
  163. // This chunk of code is not necessary because typically, users of the
  164. // stream will read until EOF. Therefore, underflow was called and the
  165. // segment was discarded before the sync() was called in the destructor.
  166. // Theoretically, we could keep some more data around and detect the rare
  167. // case where an istream was deleted before reading to the end, but that
  168. // will only leave behind some unavailable but still referenced memory.
  169. // Also, if another istream is constructed, it will re-read that segment,
  170. // and then discard it.
  171. #if 0
  172. U8* last_pos = (U8*)gptr();
  173. if (last_pos)
  174. {
  175. // Looks like we read something. Discard what we have read. gptr()
  176. // actually returns the currrent position, but we call it last_pos
  177. // because of how it is used in the split call below.
  178. --last_pos;
  179. LLBufferArray::segment_iterator_t iter = mBuffer->splitAfter(last_pos);
  180. if (iter != mBuffer->endSegment())
  181. {
  182. // We need to clear the read segment just in case we have an early
  183. // exit in the function and never collect the next segment. Calling
  184. // eraseSegment() with the same segment twice is just like double
  185. // deleting: nothing good comes from it.
  186. mBuffer->eraseSegment(iter);
  187. }
  188. }
  189. #endif
  190. // Set the put pointer so that we force an overflow on the next write.
  191. U8* address = (U8*)pptr();
  192. setp(NULL, NULL);
  193. LLMutexLock lock(mBuffer->getMutex());
  194. // *NOTE: I bet we could just --address if address is not NULL. Need to
  195. // think about that.
  196. address = mBuffer->seek(mChannels.out(), address, -1);
  197. if (address)
  198. {
  199. LLBufferArray::segment_iterator_t it = mBuffer->splitAfter(address);
  200. LLBufferArray::segment_iterator_t end = mBuffer->endSegment();
  201. if (it != end)
  202. {
  203. ++it;
  204. if (it != end)
  205. {
  206. mBuffer->eraseSegment(it);
  207. }
  208. return_value = 0;
  209. }
  210. }
  211. else
  212. {
  213. // Nothing was put on the buffer, so the sync() is a no-op.
  214. return_value = 0;
  215. }
  216. return return_value;
  217. }
  218. //virtual
  219. LLBufferStreamBuf::pos_type LLBufferStreamBuf::seekoff(LLBufferStreamBuf::off_type off,
  220. std::ios::seekdir way,
  221. std::ios::openmode which)
  222. {
  223. if (!mBuffer || (way == std::ios::beg && off < 0) ||
  224. (way == std::ios::end && off > 0))
  225. {
  226. return -1;
  227. }
  228. U8* address = NULL;
  229. if (which & std::ios::in)
  230. {
  231. U8* base_addr = NULL;
  232. switch (way)
  233. {
  234. case std::ios::end:
  235. base_addr = (U8*)LLBufferArray::npos;
  236. break;
  237. case std::ios::cur:
  238. // Het the current get pointer and adjust it for buffer array
  239. // semantics.
  240. base_addr = (U8*)gptr();
  241. break;
  242. case std::ios::beg:
  243. default:
  244. // NULL is fine
  245. break;
  246. }
  247. LLMutexLock lock(mBuffer->getMutex());
  248. address = mBuffer->seek(mChannels.in(), base_addr, off);
  249. if (address)
  250. {
  251. LLBufferArray::segment_iterator_t iter;
  252. iter = mBuffer->getSegment(address);
  253. char* start = (char*)(*iter).data();
  254. setg(start, (char*)address, start + (*iter).size());
  255. }
  256. else
  257. {
  258. address = (U8*)(-1);
  259. }
  260. }
  261. if (which & std::ios::out)
  262. {
  263. U8* base_addr = NULL;
  264. switch (way)
  265. {
  266. case std::ios::end:
  267. base_addr = (U8*)LLBufferArray::npos;
  268. break;
  269. case std::ios::cur:
  270. // Get the current put pointer and adjust it for buffer array
  271. //semantics.
  272. base_addr = (U8*)pptr();
  273. break;
  274. case std::ios::beg:
  275. default:
  276. // NULL is fine
  277. break;
  278. }
  279. LLMutexLock lock(mBuffer->getMutex());
  280. address = mBuffer->seek(mChannels.out(), base_addr, off);
  281. if (address)
  282. {
  283. LLBufferArray::segment_iterator_t iter;
  284. iter = mBuffer->getSegment(address);
  285. setp((char*)address, (char*)(*iter).data() + (*iter).size());
  286. }
  287. else
  288. {
  289. address = (U8*)(-1);
  290. }
  291. }
  292. #if (LL_WINDOWS || __GNUC__ > 2)
  293. S32 rv = (S32)(intptr_t)address;
  294. return (pos_type)rv;
  295. #else
  296. return (streampos)address;
  297. #endif
  298. }
  299. ///////////////////////////////////////////////////////////////////////////////
  300. // LLBufferStream
  301. ///////////////////////////////////////////////////////////////////////////////
  302. LLBufferStream::LLBufferStream(const LLChannelDescriptors& channels,
  303. LLBufferArray* buffer)
  304. : std::iostream(&mStreamBuf),
  305. mStreamBuf(channels, buffer)
  306. {
  307. }