Imported Upstream version 0.9.0
[deb_shairplay.git] / AirTV-Qt / qtsingleapplication / src / qtlockedfile_win.cpp
CommitLineData
15c988f7
JB
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
48Qt::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
80bool 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
99bool 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
172bool 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
200QtLockedFile::~QtLockedFile()
201{
202 if (isOpen())
203 unlock();
204 if (wmutex)
205 CloseHandle(wmutex);
206}