1 // 2 // getstream.cpp 3 // 4 // Copyright (c) Microsoft Corporation. All rights reserved. 5 // 6 // Defines _getstream(), which finds and locks a stream that is available for use. 7 // 8 #include <corecrt_internal_stdio.h> 9 10 11 12 static __crt_stdio_stream __cdecl find_or_allocate_unused_stream_nolock() throw() 13 { 14 __crt_stdio_stream_data** const first_stream = __piob + _IOB_ENTRIES; 15 __crt_stdio_stream_data** const last_stream = first_stream + _nstream - _IOB_ENTRIES; 16 17 for (__crt_stdio_stream_data** it = first_stream; it != last_stream; ++it) 18 { 19 // First, check to see whether the stream is valid and free for use: 20 { 21 __crt_stdio_stream stream(*it); 22 if (stream.valid()) 23 { 24 if (stream.is_in_use()) 25 continue; 26 27 stream.lock(); 28 if (!stream.try_allocate()) 29 { 30 stream.unlock(); 31 continue; 32 } 33 34 return stream; 35 } 36 } 37 38 // Otherwise, there is no stream at this index yet, so we allocate one 39 // and return it: 40 { 41 *it = _calloc_crt_t(__crt_stdio_stream_data, 1).detach(); 42 if (*it == nullptr) 43 break; 44 45 // Initialize the stream. Everything requires zero-initialization 46 // (which we get from calloc), except the file handle and the lock: 47 (*it)->_file = -1; 48 __acrt_InitializeCriticalSectionEx(&(*it)->_lock, _CORECRT_SPINCOUNT, 0); 49 50 __crt_stdio_stream stream(*it); 51 52 // Note: This attempt will always succeed, because we hold the only 53 // pointer to the stream object (since we just allocated it): 54 stream.try_allocate(); 55 stream.lock(); 56 57 return stream; 58 } 59 } 60 61 return __crt_stdio_stream(); 62 } 63 64 65 66 // Finds a stream not in use and makes it available to the caller. It is 67 // intended for internal use inside the library only. It returns a pointer to 68 // a free stream, or nullptr if all are in use. A stream becomes allocated 69 // only if the caller decides to use it by setting a mode (r, w, or r/w). The 70 // stream is returned locked; the caller is responsible for unlocking the stream. 71 __crt_stdio_stream __cdecl __acrt_stdio_allocate_stream() throw() 72 { 73 __crt_stdio_stream stream; 74 75 __acrt_lock(__acrt_stdio_index_lock); 76 __try 77 { 78 stream = find_or_allocate_unused_stream_nolock(); 79 if (!stream.valid()) 80 __leave; 81 82 stream->_cnt = 0; 83 stream->_tmpfname = nullptr; 84 stream->_ptr = nullptr; 85 stream->_base = nullptr; 86 stream->_file = -1; 87 } 88 __finally 89 { 90 __acrt_unlock(__acrt_stdio_index_lock); 91 } 92 __endtry 93 94 return stream; 95 } 96 97 void __cdecl __acrt_stdio_free_stream(__crt_stdio_stream stream) throw() 98 { 99 stream->_ptr = nullptr; 100 stream->_base = nullptr; 101 stream->_cnt = 0; 102 stream->_file = -1; 103 stream->_charbuf = 0; 104 stream->_bufsiz = 0; 105 stream->_tmpfname = nullptr; 106 stream.deallocate(); 107 } 108