fflush.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /* Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org>
  2. *
  3. * GNU Library General Public License (LGPL) version 2 or later.
  4. *
  5. * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details.
  6. */
  7. #include "_stdio.h"
  8. #ifdef __DO_UNLOCKED
  9. #ifdef __UCLIBC_MJN3_ONLY__
  10. #warning WISHLIST: Add option to test for undefined behavior of fflush.
  11. #endif /* __UCLIBC_MJN3_ONLY__ */
  12. /* Even if the stream is set to user-locking, we still need to lock
  13. * when all (lbf) writing streams are flushed. */
  14. #define __MY_STDIO_THREADLOCK(__stream) \
  15. __UCLIBC_IO_MUTEX_CONDITIONAL_LOCK((__stream)->__lock, \
  16. (_stdio_user_locking != 2))
  17. #define __MY_STDIO_THREADUNLOCK(__stream) \
  18. __UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK((__stream)->__lock, \
  19. (_stdio_user_locking != 2))
  20. #if defined(__UCLIBC_HAS_THREADS__) && defined(__STDIO_BUFFERS)
  21. void attribute_hidden _stdio_openlist_dec_use(void)
  22. {
  23. __STDIO_THREADLOCK_OPENLIST_DEL;
  24. if ((_stdio_openlist_use_count == 1) && (_stdio_openlist_del_count > 0)) {
  25. FILE *p = NULL;
  26. FILE *n;
  27. FILE *stream;
  28. #ifdef __UCLIBC_MJN3_ONLY__
  29. #warning REMINDER: As an optimization, we could unlock after we move past the head.
  30. #endif
  31. /* Grab the openlist add lock since we might change the head of the list. */
  32. __STDIO_THREADLOCK_OPENLIST_ADD;
  33. for (stream = _stdio_openlist; stream; stream = n) {
  34. n = stream->__nextopen;
  35. #ifdef __UCLIBC_MJN3_ONLY__
  36. #warning REMINDER: fix for nonatomic
  37. #endif
  38. if ((stream->__modeflags & (__FLAG_READONLY|__FLAG_WRITEONLY|__FLAG_FAILED_FREOPEN))
  39. == (__FLAG_READONLY|__FLAG_WRITEONLY)
  40. ) { /* The file was closed and should be removed from the list. */
  41. if (!p) {
  42. _stdio_openlist = n;
  43. } else {
  44. p->__nextopen = n;
  45. }
  46. __STDIO_STREAM_FREE_FILE(stream);
  47. } else {
  48. p = stream;
  49. }
  50. }
  51. __STDIO_THREADUNLOCK_OPENLIST_ADD;
  52. _stdio_openlist_del_count = 0; /* Should be clean now. */
  53. }
  54. --_stdio_openlist_use_count;
  55. __STDIO_THREADUNLOCK_OPENLIST_DEL;
  56. }
  57. #endif
  58. int fflush_unlocked(register FILE *stream)
  59. {
  60. #ifdef __STDIO_BUFFERS
  61. int retval = 0;
  62. #ifdef __UCLIBC_MJN3_ONLY__
  63. #warning REMINDER: should probably define a modeflags type
  64. #endif
  65. unsigned short bufmask = __FLAG_LBF;
  66. #ifndef NDEBUG
  67. if ((stream != NULL) && (stream != (FILE *) &_stdio_openlist)) {
  68. __STDIO_STREAM_VALIDATE(stream); /* debugging only */
  69. }
  70. #endif
  71. if (stream == (FILE *) &_stdio_openlist) { /* Flush all lbf streams. */
  72. stream = NULL;
  73. bufmask = 0;
  74. }
  75. if (!stream) { /* Flush all (lbf) writing streams. */
  76. __STDIO_OPENLIST_INC_USE;
  77. __STDIO_THREADLOCK_OPENLIST_ADD;
  78. stream = _stdio_openlist;
  79. __STDIO_THREADUNLOCK_OPENLIST_ADD;
  80. while(stream) {
  81. /* We only care about currently writing streams and do not want to
  82. * block trying to obtain mutexes on non-writing streams. */
  83. #warning fix for nonatomic
  84. #warning unnecessary check if no threads
  85. if (__STDIO_STREAM_IS_WRITING(stream)) { /* ONLY IF ATOMIC!!! */
  86. __MY_STDIO_THREADLOCK(stream);
  87. /* Need to check again once we have the lock. */
  88. if (!(((stream->__modeflags | bufmask)
  89. ^ (__FLAG_WRITING|__FLAG_LBF)
  90. ) & (__FLAG_WRITING|__MASK_BUFMODE))
  91. ) {
  92. if (!__STDIO_COMMIT_WRITE_BUFFER(stream)) {
  93. __STDIO_STREAM_DISABLE_PUTC(stream);
  94. __STDIO_STREAM_CLEAR_WRITING(stream);
  95. } else {
  96. retval = EOF;
  97. }
  98. }
  99. __MY_STDIO_THREADUNLOCK(stream);
  100. }
  101. stream = stream->__nextopen;
  102. }
  103. __STDIO_OPENLIST_DEC_USE;
  104. } else if (__STDIO_STREAM_IS_WRITING(stream)) {
  105. if (!__STDIO_COMMIT_WRITE_BUFFER(stream)) {
  106. __STDIO_STREAM_DISABLE_PUTC(stream);
  107. __STDIO_STREAM_CLEAR_WRITING(stream);
  108. } else {
  109. retval = EOF;
  110. }
  111. }
  112. #if 0
  113. else if (stream->__modeflags & (__MASK_READING|__FLAG_READONLY)) {
  114. /* ANSI/ISO says behavior in this case is undefined but also says you
  115. * shouldn't flush a stream you were reading from. As usual, glibc
  116. * caters to broken programs and simply ignores this. */
  117. __UNDEFINED_OR_NONPORTABLE;
  118. __STDIO_STREAM_SET_ERROR(stream);
  119. __set_errno(EBADF);
  120. retval = EOF;
  121. }
  122. #endif
  123. #ifndef NDEBUG
  124. if ((stream != NULL) && (stream != (FILE *) &_stdio_openlist)) {
  125. __STDIO_STREAM_VALIDATE(stream); /* debugging only */
  126. }
  127. #endif
  128. return retval;
  129. #else /* __STDIO_BUFFERS --------------------------------------- */
  130. #ifndef NDEBUG
  131. if ((stream != NULL)
  132. #ifdef __STDIO_HAS_OPENLIST
  133. && (stream != (FILE *) &_stdio_openlist)
  134. #endif
  135. ) {
  136. __STDIO_STREAM_VALIDATE(stream); /* debugging only */
  137. }
  138. #endif
  139. #if 0
  140. if (stream && (stream->__modeflags & (__MASK_READING|__FLAG_READONLY))) {
  141. /* ANSI/ISO says behavior in this case is undefined but also says you
  142. * shouldn't flush a stream you were reading from. As usual, glibc
  143. * caters to broken programs and simply ignores this. */
  144. __UNDEFINED_OR_NONPORTABLE;
  145. __STDIO_STREAM_SET_ERROR(stream);
  146. __set_errno(EBADF);
  147. return EOF;
  148. }
  149. #endif
  150. return 0;
  151. #endif /* __STDIO_BUFFERS */
  152. }
  153. libc_hidden_def(fflush_unlocked)
  154. #ifndef __UCLIBC_HAS_THREADS__
  155. strong_alias(fflush_unlocked,fflush)
  156. libc_hidden_def(fflush)
  157. #endif
  158. #elif defined __UCLIBC_HAS_THREADS__
  159. int fflush(register FILE *stream)
  160. {
  161. int retval;
  162. __STDIO_AUTO_THREADLOCK_VAR;
  163. if (stream
  164. #ifdef __STDIO_HAS_OPENLIST
  165. && (stream != (FILE *) &_stdio_openlist)
  166. #endif
  167. ) {
  168. __STDIO_AUTO_THREADLOCK(stream);
  169. retval = fflush_unlocked(stream);
  170. __STDIO_AUTO_THREADUNLOCK(stream);
  171. } else {
  172. retval = fflush_unlocked(stream);
  173. }
  174. return retval;
  175. }
  176. libc_hidden_def(fflush)
  177. #endif