Krita Source Code Documentation
Loading...
Searching...
No Matches
qtlockedfile_win.cpp
Go to the documentation of this file.
1// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
2// SPDX-License-Identifier: BSD-3-Clause
3
4#include "qtlockedfile.h"
5#include <qt_windows.h>
6#include <QFileInfo>
7
8#define MUTEX_PREFIX "QtLockedFile mutex "
9// Maximum number of concurrent read locks. Must not be greater than MAXIMUM_WAIT_OBJECTS
10#define MAX_READERS MAXIMUM_WAIT_OBJECTS
11
12#if QT_VERSION >= 0x050000
13#define QT_WA(unicode, ansi) unicode
14#endif
15
16Qt::HANDLE QtLockedFile::getMutexHandle(int idx, bool doCreate)
17{
18 if (mutexname.isEmpty()) {
19 QFileInfo fi(*this);
20 mutexname = QString::fromLatin1(MUTEX_PREFIX)
21 + fi.absoluteFilePath().toLower();
22 }
23 QString mname(mutexname);
24 if (idx >= 0)
25 mname += QString::number(idx);
26
27 Qt::HANDLE mutex;
28 if (doCreate) {
29 QT_WA( { mutex = CreateMutexW(NULL, FALSE, (TCHAR*)mname.utf16()); },
30 { mutex = CreateMutexA(NULL, FALSE, mname.toLocal8Bit().constData()); } );
31 if (!mutex) {
32 qErrnoWarning("QtLockedFile::lock(): CreateMutex failed");
33 return 0;
34 }
35 }
36 else {
37 QT_WA( { mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, (TCHAR*)mname.utf16()); },
38 { mutex = OpenMutexA(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, mname.toLocal8Bit().constData()); } );
39 if (!mutex) {
40 if (GetLastError() != ERROR_FILE_NOT_FOUND)
41 qErrnoWarning("QtLockedFile::lock(): OpenMutex failed");
42 return 0;
43 }
44 }
45 return mutex;
46}
47
48bool QtLockedFile::waitMutex(Qt::HANDLE mutex, bool doBlock)
49{
50 Q_ASSERT(mutex);
51 DWORD res = WaitForSingleObject(mutex, doBlock ? INFINITE : 0);
52 switch (res) {
53 case WAIT_OBJECT_0:
54 case WAIT_ABANDONED:
55 return true;
56 break;
57 case WAIT_TIMEOUT:
58 break;
59 default:
60 qErrnoWarning("QtLockedFile::lock(): WaitForSingleObject failed");
61 }
62 return false;
63}
64
65
66
67bool QtLockedFile::lock(LockMode mode, bool block)
68{
69 if (!isOpen()) {
70 qWarning("QtLockedFile::lock(): file is not opened");
71 return false;
72 }
73
74 if (mode == NoLock)
75 return unlock();
76
77 if (mode == m_lock_mode)
78 return true;
79
80 if (m_lock_mode != NoLock)
81 unlock();
82
83 if (!wmutex && !(wmutex = getMutexHandle(-1, true)))
84 return false;
85
86 if (!waitMutex(wmutex, block))
87 return false;
88
89 if (mode == ReadLock) {
90 int idx = 0;
91 for (; idx < MAX_READERS; idx++) {
92 rmutex = getMutexHandle(idx, false);
93 if (!rmutex || waitMutex(rmutex, false))
94 break;
95 CloseHandle(rmutex);
96 }
97 bool ok = true;
98 if (idx >= MAX_READERS) {
99 qWarning("QtLockedFile::lock(): too many readers");
100 rmutex = 0;
101 ok = false;
102 }
103 else if (!rmutex) {
104 rmutex = getMutexHandle(idx, true);
105 if (!rmutex || !waitMutex(rmutex, false))
106 ok = false;
107 }
108 if (!ok && rmutex) {
109 CloseHandle(rmutex);
110 rmutex = 0;
111 }
112 ReleaseMutex(wmutex);
113 if (!ok)
114 return false;
115 }
116 else {
117 Q_ASSERT(rmutexes.isEmpty());
118 for (int i = 0; i < MAX_READERS; i++) {
119 Qt::HANDLE mutex = getMutexHandle(i, false);
120 if (mutex)
121 rmutexes.append(mutex);
122 }
123 if (rmutexes.size()) {
124 DWORD res = WaitForMultipleObjects(rmutexes.size(), rmutexes.constData(),
125 TRUE, block ? INFINITE : 0);
126 if (res != WAIT_OBJECT_0 && res != WAIT_ABANDONED) {
127 if (res != WAIT_TIMEOUT)
128 qErrnoWarning("QtLockedFile::lock(): WaitForMultipleObjects failed");
129 m_lock_mode = WriteLock; // trick unlock() to clean up - semiyucky
130 unlock();
131 return false;
132 }
133 }
134 }
135
136 m_lock_mode = mode;
137 return true;
138}
139
140bool QtLockedFile::unlock()
141{
142 if (!isOpen()) {
143 qWarning("QtLockedFile::unlock(): file is not opened");
144 return false;
145 }
146
147 if (!isLocked())
148 return true;
149
150 if (m_lock_mode == ReadLock) {
151 ReleaseMutex(rmutex);
152 CloseHandle(rmutex);
153 rmutex = 0;
154 }
155 else {
156 foreach(Qt::HANDLE mutex, rmutexes) {
157 ReleaseMutex(mutex);
158 CloseHandle(mutex);
159 }
160 rmutexes.clear();
161 ReleaseMutex(wmutex);
162 }
163
164 m_lock_mode = QtLockedFile::NoLock;
165 return true;
166}
167
168QtLockedFile::~QtLockedFile()
169{
170 if (isOpen())
171 unlock();
172 if (wmutex)
173 CloseHandle(wmutex);
174}
static QMutex mutex
#define MAX_READERS
#define MUTEX_PREFIX