PageRenderTime 44ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/mediatomb-0.12.1/src/io_handler_buffer_helper.cc

#
C++ | 230 lines | 154 code | 36 blank | 40 comment | 46 complexity | 0ffbb944ffc45be2aef5f838def109fa MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. /*MT*
  2. MediaTomb - http://www.mediatomb.cc/
  3. io_handler_buffer_helper.cc - this file is part of MediaTomb.
  4. Copyright (C) 2005 Gena Batyan <bgeradz@mediatomb.cc>,
  5. Sergey 'Jin' Bostandzhyan <jin@mediatomb.cc>
  6. Copyright (C) 2006-2010 Gena Batyan <bgeradz@mediatomb.cc>,
  7. Sergey 'Jin' Bostandzhyan <jin@mediatomb.cc>,
  8. Leonhard Wimmer <leo@mediatomb.cc>
  9. MediaTomb is free software; you can redistribute it and/or modify
  10. it under the terms of the GNU General Public License version 2
  11. as published by the Free Software Foundation.
  12. MediaTomb is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU General Public License for more details.
  16. You should have received a copy of the GNU General Public License
  17. version 2 along with MediaTomb; if not, write to the Free Software
  18. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
  19. $Id: io_handler_buffer_helper.cc 2081 2010-03-23 20:18:00Z lww $
  20. */
  21. /// \file io_handler_buffer_helper.cc
  22. #ifdef HAVE_CONFIG_H
  23. #include "autoconfig.h"
  24. #endif
  25. #include "io_handler_buffer_helper.h"
  26. #include "config_manager.h"
  27. #include "tools.h"
  28. using namespace zmm;
  29. IOHandlerBufferHelper::IOHandlerBufferHelper(size_t bufSize, size_t initialFillSize) : IOHandler()
  30. {
  31. if (bufSize <=0)
  32. throw _Exception(_("bufSize must be positive"));
  33. if (initialFillSize < 0 || initialFillSize > bufSize)
  34. throw _Exception(_("initialFillSize must be non-negative and must be lesser than or equal to the size of the buffer"));
  35. mutex = Ref<Mutex>(new Mutex());
  36. cond = Ref<Cond>(new Cond(mutex));
  37. this->bufSize = bufSize;
  38. this->initialFillSize = initialFillSize;
  39. waitForInitialFillSize = (initialFillSize > 0);
  40. buffer = NULL;
  41. isOpen = false;
  42. threadShutdown = false;
  43. eof = false;
  44. readError = false;
  45. a = b = posRead = 0;
  46. empty = true;
  47. signalAfterEveryRead = false;
  48. checkSocket = false;
  49. seekEnabled = false;
  50. doSeek = false;
  51. }
  52. void IOHandlerBufferHelper::open(IN enum UpnpOpenFileMode mode)
  53. {
  54. if (isOpen)
  55. throw _Exception(_("tried to reopen an open IOHandlerBufferHelper"));
  56. buffer = (char *)MALLOC(bufSize);
  57. if (buffer == NULL)
  58. throw _Exception(_("Failed to allocate memory for transcoding buffer!"));
  59. startBufferThread();
  60. isOpen = true;
  61. }
  62. IOHandlerBufferHelper::~IOHandlerBufferHelper()
  63. {
  64. if (isOpen)
  65. close();
  66. }
  67. int IOHandlerBufferHelper::read(OUT char *buf, IN size_t length)
  68. {
  69. // check read on closed BufferedIOHandler
  70. assert(isOpen);
  71. // length must be positive
  72. assert(length > 0);
  73. AUTOLOCK(mutex);
  74. while ((empty || waitForInitialFillSize) && ! (threadShutdown || eof || readError))
  75. {
  76. if (checkSocket)
  77. {
  78. checkSocket = false;
  79. return CHECK_SOCKET;
  80. }
  81. else
  82. cond->wait();
  83. }
  84. if (readError || threadShutdown)
  85. return -1;
  86. if (empty && eof)
  87. return 0;
  88. size_t bLocal = b;
  89. AUTOUNLOCK();
  90. // we ensured with the while above that the buffer isn't empty
  91. int currentFillSize = bLocal - a;
  92. if (currentFillSize <= 0)
  93. currentFillSize += bufSize;
  94. size_t maxRead1 = (a < bLocal ? bLocal - a : bufSize - a);
  95. size_t read1 = (maxRead1 > length ? length : maxRead1);
  96. size_t maxRead2 = currentFillSize - read1;
  97. size_t read2 = (read1 < length ? length - read1 : 0);
  98. if (read2 > maxRead2)
  99. read2 = maxRead2;
  100. memcpy(buf, buffer + a, read1);
  101. if (read2)
  102. memcpy(buf + read1, buffer, read2);
  103. size_t didRead = read1+read2;
  104. AUTORELOCK();
  105. bool signalled = false;
  106. // was the buffer full or became it "full" while we read?
  107. if (signalAfterEveryRead || a == b)
  108. {
  109. cond->signal();
  110. signalled = true;
  111. }
  112. a += didRead;
  113. if (a >= bufSize)
  114. a -= bufSize;
  115. if (a == b)
  116. {
  117. empty = true;
  118. if (! signalled)
  119. cond->signal();
  120. }
  121. posRead += didRead;
  122. return didRead;
  123. }
  124. void IOHandlerBufferHelper::seek(IN off_t offset, IN int whence)
  125. {
  126. log_debug("seek called: %lld %d\n", offset, whence);
  127. if (! seekEnabled)
  128. throw _Exception(_("seek currently disabled in this IOHandlerBufferHelper"));
  129. assert(isOpen);
  130. // check for valid input
  131. assert(whence == SEEK_SET || whence == SEEK_CUR || whence == SEEK_END);
  132. assert(whence != SEEK_SET || offset >= 0);
  133. assert(whence != SEEK_END || offset <= 0);
  134. // do nothing in this case
  135. if (whence == SEEK_CUR && offset == 0)
  136. return;
  137. AUTOLOCK(mutex);
  138. // if another seek isn't processed yet - well we don't care as this new seek
  139. // will change the position anyway
  140. doSeek = true;
  141. seekOffset = offset;
  142. seekWhence = whence;
  143. // tell the probably sleeping thread to process our seek
  144. cond->signal();
  145. // wait until the seek has been processed
  146. while(doSeek && ! (threadShutdown || eof || readError))
  147. cond->wait();
  148. }
  149. void IOHandlerBufferHelper::close()
  150. {
  151. if (! isOpen)
  152. throw _Exception(_("close called on closed IOHandlerBufferHelper"));
  153. isOpen = false;
  154. stopBufferThread();
  155. FREE(buffer);
  156. buffer = NULL;
  157. }
  158. // thread stuff...
  159. void IOHandlerBufferHelper::startBufferThread()
  160. {
  161. pthread_create(
  162. &bufferThread,
  163. NULL, // attr
  164. IOHandlerBufferHelper::staticThreadProc,
  165. this
  166. );
  167. }
  168. void IOHandlerBufferHelper::stopBufferThread()
  169. {
  170. AUTOLOCK(mutex);
  171. threadShutdown = true;
  172. cond->signal();
  173. AUTOUNLOCK();
  174. if (bufferThread)
  175. pthread_join(bufferThread, NULL);
  176. bufferThread = 0;
  177. }
  178. void *IOHandlerBufferHelper::staticThreadProc(void *arg)
  179. {
  180. log_debug("starting buffer thread... thread: %d\n", pthread_self());
  181. IOHandlerBufferHelper *inst = (IOHandlerBufferHelper *)arg;
  182. inst->threadProc();
  183. log_debug("buffer thread shut down. thread: %d\n", pthread_self());
  184. pthread_exit(NULL);
  185. return NULL;
  186. }