1737 |
: List(this), bIsNewFile(true), Layout(layout_standard), |
: List(this), bIsNewFile(true), Layout(layout_standard), |
1738 |
FileOffsetPreference(offset_size_auto) |
FileOffsetPreference(offset_size_auto) |
1739 |
{ |
{ |
1740 |
|
io.isPerThread = false; |
1741 |
#if defined(WIN32) |
#if defined(WIN32) |
1742 |
io.hRead = io.hWrite = INVALID_HANDLE_VALUE; |
io.hRead = io.hWrite = INVALID_HANDLE_VALUE; |
1743 |
#else |
#else |
1833 |
* given RIFF file or RIFF-alike file |
* given RIFF file or RIFF-alike file |
1834 |
*/ |
*/ |
1835 |
void File::__openExistingFile(const String& path, uint32_t* FileType) { |
void File::__openExistingFile(const String& path, uint32_t* FileType) { |
1836 |
|
io.isPerThread = false; |
1837 |
#if POSIX |
#if POSIX |
1838 |
io.hRead = io.hWrite = open(path.c_str(), O_RDONLY | O_NONBLOCK); |
io.hRead = io.hWrite = open(path.c_str(), O_RDONLY | O_NONBLOCK); |
1839 |
if (io.hRead == -1) { |
if (io.hRead == -1) { |
1994 |
* @see File::IsIOPerThread() for multi-threaded streaming |
* @see File::IsIOPerThread() for multi-threaded streaming |
1995 |
*/ |
*/ |
1996 |
bool File::SetMode(stream_mode_t NewMode) { |
bool File::SetMode(stream_mode_t NewMode) { |
1997 |
|
bool bResetPos = false; |
1998 |
|
bool res = SetModeInternal(NewMode, &bResetPos); |
1999 |
|
// resetting position must be handled outside above's call to avoid any |
2000 |
|
// potential dead lock, as SetModeInternal() acquires a lock and |
2001 |
|
// __resetPos() acquires a lock by itself (not a theoretical issue!) |
2002 |
|
if (bResetPos) |
2003 |
|
__resetPos(); // reset read/write position of ALL 'Chunk' objects |
2004 |
|
return res; |
2005 |
|
} |
2006 |
|
|
2007 |
|
bool File::SetModeInternal(stream_mode_t NewMode, bool* pResetPos) { |
2008 |
std::lock_guard<std::mutex> lock(io.mutex); |
std::lock_guard<std::mutex> lock(io.mutex); |
2009 |
HandlePair& io = FileHandlePairUnsafeRef(); |
HandlePair& io = FileHandlePairUnsafeRef(); |
2010 |
if (NewMode != io.Mode) { |
if (NewMode != io.Mode) { |
2035 |
io.hRead = io.hWrite = fopen(Filename.c_str(), "rb"); |
io.hRead = io.hWrite = fopen(Filename.c_str(), "rb"); |
2036 |
if (!io.hRead) throw Exception("Could not (re)open file \"" + Filename + "\" in read mode"); |
if (!io.hRead) throw Exception("Could not (re)open file \"" + Filename + "\" in read mode"); |
2037 |
#endif |
#endif |
2038 |
__resetPos(); // reset read/write position of ALL 'Chunk' objects |
*pResetPos = true; |
2039 |
break; |
break; |
2040 |
case stream_mode_read_write: |
case stream_mode_read_write: |
2041 |
if (_isValidHandle(io.hRead)) _close(io.hRead); |
if (_isValidHandle(io.hRead)) _close(io.hRead); |
2074 |
throw Exception("Could not open file \"" + Filename + "\" in read+write mode"); |
throw Exception("Could not open file \"" + Filename + "\" in read+write mode"); |
2075 |
} |
} |
2076 |
#endif |
#endif |
2077 |
__resetPos(); // reset read/write position of ALL 'Chunk' objects |
*pResetPos = true; |
2078 |
break; |
break; |
2079 |
case stream_mode_closed: |
case stream_mode_closed: |
2080 |
if (_isValidHandle(io.hRead)) _close(io.hRead); |
if (_isValidHandle(io.hRead)) _close(io.hRead); |
2533 |
* @see SetIOPerThread() |
* @see SetIOPerThread() |
2534 |
*/ |
*/ |
2535 |
bool File::IsIOPerThread() const { |
bool File::IsIOPerThread() const { |
2536 |
std::lock_guard<std::mutex> lock(io.mutex); |
//NOTE: Not caring about atomicity here at all, for three reasons: |
2537 |
return !io.byThread.empty(); |
// 1. SetIOPerThread() is assumed to be called only once for the entire |
2538 |
|
// life time of a RIFF::File, usually very early at its lifetime, and |
2539 |
|
// hence a change to isPerThread should already safely be propagated |
2540 |
|
// before any other thread would actually read this boolean flag. |
2541 |
|
// 2. This method is called very frequently, and therefore any |
2542 |
|
// synchronization techique would hurt runtime efficiency. |
2543 |
|
// 3. Using even a mutex lock here might easily cause a deadlock due to |
2544 |
|
// other locks been taken in this .cpp file, i.e. at a higher call |
2545 |
|
// stack level (and this is the main reason why I removed it here). |
2546 |
|
return io.isPerThread; |
2547 |
} |
} |
2548 |
|
|
2549 |
/** @brief Enable/disable file streams being independent for each thread. |
/** @brief Enable/disable file streams being independent for each thread. |
2564 |
void File::SetIOPerThread(bool enable) { |
void File::SetIOPerThread(bool enable) { |
2565 |
std::lock_guard<std::mutex> lock(io.mutex); |
std::lock_guard<std::mutex> lock(io.mutex); |
2566 |
if (!io.byThread.empty() == enable) return; |
if (!io.byThread.empty() == enable) return; |
2567 |
|
io.isPerThread = enable; |
2568 |
if (enable) { |
if (enable) { |
2569 |
const std::thread::id tid = std::this_thread::get_id(); |
const std::thread::id tid = std::this_thread::get_id(); |
2570 |
io.byThread[tid] = io; |
io.byThread[tid] = io; |