fflush.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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. if (__STDIO_STREAM_IS_WRITING(stream)) { /* ONLY IF ATOMIC!!! */
  84. __MY_STDIO_THREADLOCK(stream);
  85. /* Need to check again once we have the lock. */
  86. if (!(((stream->__modeflags | bufmask)
  87. ^ (__FLAG_WRITING|__FLAG_LBF)
  88. ) & (__FLAG_WRITING|__MASK_BUFMODE))
  89. ) {
  90. if (!__STDIO_COMMIT_WRITE_BUFFER(stream)) {
  91. __STDIO_STREAM_DISABLE_PUTC(stream);
  92. __STDIO_STREAM_CLEAR_WRITING(stream);
  93. } else {
  94. retval = EOF;
  95. }
  96. }
  97. __MY_STDIO_THREADUNLOCK(stream);
  98. }
  99. stream = stream->__nextopen;
  100. }
  101. __STDIO_OPENLIST_DEC_USE;
  102. } else if (__STDIO_STREAM_IS_WRITING(stream)) {
  103. if (!__STDIO_COMMIT_WRITE_BUFFER(stream)) {
  104. __STDIO_STREAM_DISABLE_PUTC(stream);
  105. __STDIO_STREAM_CLEAR_WRITING(stream);
  106. } else {
  107. retval = EOF;
  108. }
  109. }
  110. #if 0
  111. else if (stream->__modeflags & (__MASK_READING|__FLAG_READONLY)) {
  112. /* ANSI/ISO says behavior in this case is undefined but also says you
  113. * shouldn't flush a stream you were reading from. As usual, glibc
  114. * caters to broken programs and simply ignores this. */
  115. __UNDEFINED_OR_NONPORTABLE;
  116. __STDIO_STREAM_SET_ERROR(stream);
  117. __set_errno(EBADF);
  118. retval = EOF;
  119. }
  120. #endif
  121. #ifndef NDEBUG
  122. if ((stream != NULL) && (stream != (FILE *) &_stdio_openlist)) {
  123. __STDIO_STREAM_VALIDATE(stream); /* debugging only */
  124. }
  125. #endif
  126. return retval;
  127. #else /* __STDIO_BUFFERS --------------------------------------- */
  128. #ifndef NDEBUG
  129. if ((stream != NULL)
  130. #ifdef __STDIO_HAS_OPENLIST
  131. && (stream != (FILE *) &_stdio_openlist)
  132. #endif
  133. ) {
  134. __STDIO_STREAM_VALIDATE(stream); /* debugging only */
  135. }
  136. #endif
  137. #if 0
  138. if (stream && (stream->__modeflags & (__MASK_READING|__FLAG_READONLY))) {
  139. /* ANSI/ISO says behavior in this case is undefined but also says you
  140. * shouldn't flush a stream you were reading from. As usual, glibc
  141. * caters to broken programs and simply ignores this. */
  142. __UNDEFINED_OR_NONPORTABLE;
  143. __STDIO_STREAM_SET_ERROR(stream);
  144. __set_errno(EBADF);
  145. return EOF;
  146. }
  147. #endif
  148. return 0;
  149. #endif /* __STDIO_BUFFERS */
  150. }
  151. libc_hidden_def(fflush_unlocked)
  152. #ifndef __UCLIBC_HAS_THREADS__
  153. strong_alias(fflush_unlocked,fflush)
  154. libc_hidden_def(fflush)
  155. #endif
  156. #elif defined __UCLIBC_HAS_THREADS__
  157. int fflush(register FILE *stream)
  158. {
  159. int retval;
  160. __STDIO_AUTO_THREADLOCK_VAR;
  161. if (stream
  162. #ifdef __STDIO_HAS_OPENLIST
  163. && (stream != (FILE *) &_stdio_openlist)
  164. #endif
  165. ) {
  166. __STDIO_AUTO_THREADLOCK(stream);
  167. retval = fflush_unlocked(stream);
  168. __STDIO_AUTO_THREADUNLOCK(stream);
  169. } else {
  170. retval = fflush_unlocked(stream);
  171. }
  172. return retval;
  173. }
  174. libc_hidden_def(fflush)
  175. #endif