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