BufferedTextOutput.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /*
  2. * Copyright (C) 2006 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <binder/BufferedTextOutput.h>
  17. #include <binder/Debug.h>
  18. #include <cutils/atomic.h>
  19. #include <cutils/threads.h>
  20. #include <utils/Log.h>
  21. #include <utils/RefBase.h>
  22. #include <utils/Vector.h>
  23. #include <private/binder/Static.h>
  24. #include <pthread.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. // ---------------------------------------------------------------------------
  28. namespace android {
  29. struct BufferedTextOutput::BufferState : public RefBase
  30. {
  31. explicit BufferState(int32_t _seq)
  32. : seq(_seq)
  33. , buffer(nullptr)
  34. , bufferPos(0)
  35. , bufferSize(0)
  36. , atFront(true)
  37. , indent(0)
  38. , bundle(0) {
  39. }
  40. ~BufferState() {
  41. free(buffer);
  42. }
  43. status_t append(const char* txt, size_t len) {
  44. if ((len+bufferPos) > bufferSize) {
  45. size_t newSize = ((len+bufferPos)*3)/2;
  46. if (newSize < (len+bufferPos)) return NO_MEMORY; // overflow
  47. void* b = realloc(buffer, newSize);
  48. if (!b) return NO_MEMORY;
  49. buffer = (char*)b;
  50. bufferSize = newSize;
  51. }
  52. memcpy(buffer+bufferPos, txt, len);
  53. bufferPos += len;
  54. return NO_ERROR;
  55. }
  56. void restart() {
  57. bufferPos = 0;
  58. atFront = true;
  59. if (bufferSize > 256) {
  60. void* b = realloc(buffer, 256);
  61. if (b) {
  62. buffer = (char*)b;
  63. bufferSize = 256;
  64. }
  65. }
  66. }
  67. const int32_t seq;
  68. char* buffer;
  69. size_t bufferPos;
  70. size_t bufferSize;
  71. bool atFront;
  72. int32_t indent;
  73. int32_t bundle;
  74. };
  75. struct BufferedTextOutput::ThreadState
  76. {
  77. Vector<sp<BufferedTextOutput::BufferState> > states;
  78. };
  79. static pthread_mutex_t gMutex = PTHREAD_MUTEX_INITIALIZER;
  80. static thread_store_t tls;
  81. BufferedTextOutput::ThreadState* BufferedTextOutput::getThreadState()
  82. {
  83. ThreadState* ts = (ThreadState*) thread_store_get( &tls );
  84. if (ts) return ts;
  85. ts = new ThreadState;
  86. thread_store_set( &tls, ts, threadDestructor );
  87. return ts;
  88. }
  89. void BufferedTextOutput::threadDestructor(void *st)
  90. {
  91. delete ((ThreadState*)st);
  92. }
  93. static volatile int32_t gSequence = 0;
  94. static volatile int32_t gFreeBufferIndex = -1;
  95. static int32_t allocBufferIndex()
  96. {
  97. int32_t res = -1;
  98. pthread_mutex_lock(&gMutex);
  99. if (gFreeBufferIndex >= 0) {
  100. res = gFreeBufferIndex;
  101. gFreeBufferIndex = gTextBuffers[res];
  102. gTextBuffers.editItemAt(res) = -1;
  103. } else {
  104. res = gTextBuffers.size();
  105. gTextBuffers.add(-1);
  106. }
  107. pthread_mutex_unlock(&gMutex);
  108. return res;
  109. }
  110. static void freeBufferIndex(int32_t idx)
  111. {
  112. pthread_mutex_lock(&gMutex);
  113. gTextBuffers.editItemAt(idx) = gFreeBufferIndex;
  114. gFreeBufferIndex = idx;
  115. pthread_mutex_unlock(&gMutex);
  116. }
  117. // ---------------------------------------------------------------------------
  118. BufferedTextOutput::BufferedTextOutput(uint32_t flags)
  119. : mFlags(flags)
  120. , mSeq(android_atomic_inc(&gSequence))
  121. , mIndex(allocBufferIndex())
  122. {
  123. mGlobalState = new BufferState(mSeq);
  124. if (mGlobalState) mGlobalState->incStrong(this);
  125. }
  126. BufferedTextOutput::~BufferedTextOutput()
  127. {
  128. if (mGlobalState) mGlobalState->decStrong(this);
  129. freeBufferIndex(mIndex);
  130. }
  131. status_t BufferedTextOutput::print(const char* txt, size_t len)
  132. {
  133. //printf("BufferedTextOutput: printing %d\n", len);
  134. AutoMutex _l(mLock);
  135. BufferState* b = getBuffer();
  136. const char* const end = txt+len;
  137. status_t err;
  138. while (txt < end) {
  139. // Find the next line.
  140. const char* first = txt;
  141. while (txt < end && *txt != '\n') txt++;
  142. // Include this and all following empty lines.
  143. while (txt < end && *txt == '\n') txt++;
  144. // Special cases for first data on a line.
  145. if (b->atFront) {
  146. if (b->indent > 0) {
  147. // If this is the start of a line, add the indent.
  148. const char* prefix = stringForIndent(b->indent);
  149. err = b->append(prefix, strlen(prefix));
  150. if (err != NO_ERROR) return err;
  151. } else if (*(txt-1) == '\n' && !b->bundle) {
  152. // Fast path: if we are not indenting or bundling, and
  153. // have been given one or more complete lines, just write
  154. // them out without going through the buffer.
  155. // Slurp up all of the lines.
  156. const char* lastLine = txt;
  157. while (txt < end) {
  158. if (*txt++ == '\n') lastLine = txt;
  159. }
  160. struct iovec vec;
  161. vec.iov_base = (void*)first;
  162. vec.iov_len = lastLine-first;
  163. //printf("Writing %d bytes of data!\n", vec.iov_len);
  164. writeLines(vec, 1);
  165. txt = lastLine;
  166. continue;
  167. }
  168. }
  169. // Append the new text to the buffer.
  170. err = b->append(first, txt-first);
  171. if (err != NO_ERROR) return err;
  172. b->atFront = *(txt-1) == '\n';
  173. // If we have finished a line and are not bundling, write
  174. // it out.
  175. //printf("Buffer is now %d bytes\n", b->bufferPos);
  176. if (b->atFront && !b->bundle) {
  177. struct iovec vec;
  178. vec.iov_base = b->buffer;
  179. vec.iov_len = b->bufferPos;
  180. //printf("Writing %d bytes of data!\n", vec.iov_len);
  181. writeLines(vec, 1);
  182. b->restart();
  183. }
  184. }
  185. return NO_ERROR;
  186. }
  187. void BufferedTextOutput::moveIndent(int delta)
  188. {
  189. AutoMutex _l(mLock);
  190. BufferState* b = getBuffer();
  191. b->indent += delta;
  192. if (b->indent < 0) b->indent = 0;
  193. }
  194. void BufferedTextOutput::pushBundle()
  195. {
  196. AutoMutex _l(mLock);
  197. BufferState* b = getBuffer();
  198. b->bundle++;
  199. }
  200. void BufferedTextOutput::popBundle()
  201. {
  202. AutoMutex _l(mLock);
  203. BufferState* b = getBuffer();
  204. b->bundle--;
  205. LOG_FATAL_IF(b->bundle < 0,
  206. "TextOutput::popBundle() called more times than pushBundle()");
  207. if (b->bundle < 0) b->bundle = 0;
  208. if (b->bundle == 0) {
  209. // Last bundle, write out data if it is complete. If it is not
  210. // complete, don't write until the last line is done... this may
  211. // or may not be the write thing to do, but it's the easiest.
  212. if (b->bufferPos > 0 && b->atFront) {
  213. struct iovec vec;
  214. vec.iov_base = b->buffer;
  215. vec.iov_len = b->bufferPos;
  216. writeLines(vec, 1);
  217. b->restart();
  218. }
  219. }
  220. }
  221. BufferedTextOutput::BufferState* BufferedTextOutput::getBuffer() const
  222. {
  223. if ((mFlags&MULTITHREADED) != 0) {
  224. ThreadState* ts = getThreadState();
  225. if (ts) {
  226. while (ts->states.size() <= (size_t)mIndex) ts->states.add(nullptr);
  227. BufferState* bs = ts->states[mIndex].get();
  228. if (bs != nullptr && bs->seq == mSeq) return bs;
  229. ts->states.editItemAt(mIndex) = new BufferState(mIndex);
  230. bs = ts->states[mIndex].get();
  231. if (bs != nullptr) return bs;
  232. }
  233. }
  234. return mGlobalState;
  235. }
  236. }; // namespace android