Imported Upstream version 0.9.0
[deb_shairplay.git] / AirTV-Qt / qtsingleapplication / src / qtlockedfile_win.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 **
6 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 **
8 ** This file is part of a Qt Solutions component.
9 **
10 ** You may use this file under the terms of the BSD license as follows:
11 **
12 ** "Redistribution and use in source and binary forms, with or without
13 ** modification, are permitted provided that the following conditions are
14 ** met:
15 ** * Redistributions of source code must retain the above copyright
16 ** notice, this list of conditions and the following disclaimer.
17 ** * Redistributions in binary form must reproduce the above copyright
18 ** notice, this list of conditions and the following disclaimer in
19 ** the documentation and/or other materials provided with the
20 ** distribution.
21 ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
22 ** the names of its contributors may be used to endorse or promote
23 ** products derived from this software without specific prior written
24 ** permission.
25 **
26 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
37 **
38 ****************************************************************************/
39
40 #include "qtlockedfile.h"
41 #include <qt_windows.h>
42 #include <QtCore/QFileInfo>
43
44 #define MUTEX_PREFIX "QtLockedFile mutex "
45 // Maximum number of concurrent read locks. Must not be greater than MAXIMUM_WAIT_OBJECTS
46 #define MAX_READERS MAXIMUM_WAIT_OBJECTS
47
48 Qt::HANDLE QtLockedFile::getMutexHandle(int idx, bool doCreate)
49 {
50 if (mutexname.isEmpty()) {
51 QFileInfo fi(*this);
52 mutexname = QString::fromLatin1(MUTEX_PREFIX)
53 + fi.absoluteFilePath().toLower();
54 }
55 QString mname(mutexname);
56 if (idx >= 0)
57 mname += QString::number(idx);
58
59 Qt::HANDLE mutex;
60 if (doCreate) {
61 QT_WA( { mutex = CreateMutexW(NULL, FALSE, (TCHAR*)mname.utf16()); },
62 { mutex = CreateMutexA(NULL, FALSE, mname.toLocal8Bit().constData()); } );
63 if (!mutex) {
64 qErrnoWarning("QtLockedFile::lock(): CreateMutex failed");
65 return 0;
66 }
67 }
68 else {
69 QT_WA( { mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, (TCHAR*)mname.utf16()); },
70 { mutex = OpenMutexA(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, mname.toLocal8Bit().constData()); } );
71 if (!mutex) {
72 if (GetLastError() != ERROR_FILE_NOT_FOUND)
73 qErrnoWarning("QtLockedFile::lock(): OpenMutex failed");
74 return 0;
75 }
76 }
77 return mutex;
78 }
79
80 bool QtLockedFile::waitMutex(Qt::HANDLE mutex, bool doBlock)
81 {
82 Q_ASSERT(mutex);
83 DWORD res = WaitForSingleObject(mutex, doBlock ? INFINITE : 0);
84 switch (res) {
85 case WAIT_OBJECT_0:
86 case WAIT_ABANDONED:
87 return true;
88 break;
89 case WAIT_TIMEOUT:
90 break;
91 default:
92 qErrnoWarning("QtLockedFile::lock(): WaitForSingleObject failed");
93 }
94 return false;
95 }
96
97
98
99 bool QtLockedFile::lock(LockMode mode, bool block)
100 {
101 if (!isOpen()) {
102 qWarning("QtLockedFile::lock(): file is not opened");
103 return false;
104 }
105
106 if (mode == NoLock)
107 return unlock();
108
109 if (mode == m_lock_mode)
110 return true;
111
112 if (m_lock_mode != NoLock)
113 unlock();
114
115 if (!wmutex && !(wmutex = getMutexHandle(-1, true)))
116 return false;
117
118 if (!waitMutex(wmutex, block))
119 return false;
120
121 if (mode == ReadLock) {
122 int idx = 0;
123 for (; idx < MAX_READERS; idx++) {
124 rmutex = getMutexHandle(idx, false);
125 if (!rmutex || waitMutex(rmutex, false))
126 break;
127 CloseHandle(rmutex);
128 }
129 bool ok = true;
130 if (idx >= MAX_READERS) {
131 qWarning("QtLockedFile::lock(): too many readers");
132 rmutex = 0;
133 ok = false;
134 }
135 else if (!rmutex) {
136 rmutex = getMutexHandle(idx, true);
137 if (!rmutex || !waitMutex(rmutex, false))
138 ok = false;
139 }
140 if (!ok && rmutex) {
141 CloseHandle(rmutex);
142 rmutex = 0;
143 }
144 ReleaseMutex(wmutex);
145 if (!ok)
146 return false;
147 }
148 else {
149 Q_ASSERT(rmutexes.isEmpty());
150 for (int i = 0; i < MAX_READERS; i++) {
151 Qt::HANDLE mutex = getMutexHandle(i, false);
152 if (mutex)
153 rmutexes.append(mutex);
154 }
155 if (rmutexes.size()) {
156 DWORD res = WaitForMultipleObjects(rmutexes.size(), rmutexes.constData(),
157 TRUE, block ? INFINITE : 0);
158 if (res != WAIT_OBJECT_0 && res != WAIT_ABANDONED) {
159 if (res != WAIT_TIMEOUT)
160 qErrnoWarning("QtLockedFile::lock(): WaitForMultipleObjects failed");
161 m_lock_mode = WriteLock; // trick unlock() to clean up - semiyucky
162 unlock();
163 return false;
164 }
165 }
166 }
167
168 m_lock_mode = mode;
169 return true;
170 }
171
172 bool QtLockedFile::unlock()
173 {
174 if (!isOpen()) {
175 qWarning("QtLockedFile::unlock(): file is not opened");
176 return false;
177 }
178
179 if (!isLocked())
180 return true;
181
182 if (m_lock_mode == ReadLock) {
183 ReleaseMutex(rmutex);
184 CloseHandle(rmutex);
185 rmutex = 0;
186 }
187 else {
188 foreach(Qt::HANDLE mutex, rmutexes) {
189 ReleaseMutex(mutex);
190 CloseHandle(mutex);
191 }
192 rmutexes.clear();
193 ReleaseMutex(wmutex);
194 }
195
196 m_lock_mode = QtLockedFile::NoLock;
197 return true;
198 }
199
200 QtLockedFile::~QtLockedFile()
201 {
202 if (isOpen())
203 unlock();
204 if (wmutex)
205 CloseHandle(wmutex);
206 }