OSDN Git Service

Update license.
[qt-creator-jp/qt-creator-jp.git] / src / shared / qtlockedfile / qtlockedfile_win.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
8 **
9 **
10 ** GNU Lesser General Public License Usage
11 **
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 **
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 **
23 ** Other Usage
24 **
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **************************************************************************/
32
33 #include "qtlockedfile.h"
34
35 #include <qt_windows.h>
36 #include <QtCore/QFileInfo>
37
38 namespace SharedTools {
39
40 #define SEMAPHORE_PREFIX "QtLockedFile semaphore "
41 #define MUTEX_PREFIX "QtLockedFile mutex "
42 #define SEMAPHORE_MAX 100
43
44 static QString errorCodeToString(DWORD errorCode)
45 {
46     QString result;
47     char *data = 0;
48     FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
49                     0, errorCode, 0,
50                     (char*)&data, 0, 0);
51     result = QString::fromLocal8Bit(data);
52     if (data != 0)
53         LocalFree(data);
54
55     if (result.endsWith('\n'))
56         result.truncate(result.length() - 1);
57
58     return result;
59 }
60
61 bool QtLockedFile::lock(LockMode mode, bool block)
62 {
63     if (!isOpen()) {
64         qWarning("QtLockedFile::lock(): file is not opened");
65         return false;
66     }
67
68     if (mode == m_lock_mode)
69         return true;
70
71     if (m_lock_mode != 0)
72         unlock();
73
74     if (m_semaphore_hnd == 0) {
75         QFileInfo fi(*this);
76         QString sem_name = QString::fromLatin1(SEMAPHORE_PREFIX)
77                            + fi.absoluteFilePath().toLower();
78
79         QT_WA( {
80             m_semaphore_hnd = CreateSemaphoreW(0, SEMAPHORE_MAX, SEMAPHORE_MAX,
81                                                (TCHAR*)sem_name.utf16());
82         } , {
83             m_semaphore_hnd = CreateSemaphoreA(0, SEMAPHORE_MAX, SEMAPHORE_MAX,
84                                                sem_name.toLocal8Bit().constData());
85         } );
86
87         if (m_semaphore_hnd == 0) {
88             qWarning("QtLockedFile::lock(): CreateSemaphore: %s",
89                      errorCodeToString(GetLastError()).toLatin1().constData());
90             return false;
91         }
92     }
93
94     bool gotMutex = false;
95     int decrement;
96     if (mode == ReadLock) {
97         decrement = 1;
98     } else {
99         decrement = SEMAPHORE_MAX;
100         if (m_mutex_hnd == 0) {
101             QFileInfo fi(*this);
102             QString mut_name = QString::fromLatin1(MUTEX_PREFIX)
103                                + fi.absoluteFilePath().toLower();
104             QT_WA( {
105                     m_mutex_hnd = CreateMutexW(NULL, FALSE, (TCHAR*)mut_name.utf16());
106                 } , {
107                     m_mutex_hnd = CreateMutexA(NULL, FALSE, mut_name.toLocal8Bit().constData());
108             } );
109
110             if (m_mutex_hnd == 0) {
111                 qWarning("QtLockedFile::lock(): CreateMutex: %s",
112                          errorCodeToString(GetLastError()).toLatin1().constData());
113                 return false;
114             }
115         }
116         DWORD res = WaitForSingleObject(m_mutex_hnd, block ? INFINITE : 0);
117         if (res == WAIT_TIMEOUT)
118             return false;
119         if (res == WAIT_FAILED) {
120             qWarning("QtLockedFile::lock(): WaitForSingleObject (mutex): %s",
121                      errorCodeToString(GetLastError()).toLatin1().constData());
122             return false;
123         }
124         gotMutex = true;
125     }
126
127     for (int i = 0; i < decrement; ++i) {
128         DWORD res = WaitForSingleObject(m_semaphore_hnd, block ? INFINITE : 0);
129         if (res == WAIT_TIMEOUT) {
130             if (i) {
131                 // A failed nonblocking rw locking. Undo changes to semaphore.
132                 if (ReleaseSemaphore(m_semaphore_hnd, i, NULL) == 0) {
133                     qWarning("QtLockedFile::unlock(): ReleaseSemaphore: %s",
134                              errorCodeToString(GetLastError()).toLatin1().constData());
135                     // Fall through
136                 }
137             }
138             if (gotMutex)
139                 ReleaseMutex(m_mutex_hnd);
140             return false;
141         }
142         if (res != WAIT_OBJECT_0) {
143             if (gotMutex)
144                 ReleaseMutex(m_mutex_hnd);
145             qWarning("QtLockedFile::lock(): WaitForSingleObject (semaphore): %s",
146                         errorCodeToString(GetLastError()).toLatin1().constData());
147             return false;
148         }
149     }
150
151     m_lock_mode = mode;
152     if (gotMutex)
153         ReleaseMutex(m_mutex_hnd);
154     return true;
155 }
156
157 bool QtLockedFile::unlock()
158 {
159     if (!isOpen()) {
160         qWarning("QtLockedFile::unlock(): file is not opened");
161         return false;
162     }
163
164     if (!isLocked())
165         return true;
166
167     int increment;
168     if (m_lock_mode == ReadLock)
169         increment = 1;
170     else
171         increment = SEMAPHORE_MAX;
172
173     DWORD ret = ReleaseSemaphore(m_semaphore_hnd, increment, 0);
174     if (ret == 0) {
175         qWarning("QtLockedFile::unlock(): ReleaseSemaphore: %s",
176                     errorCodeToString(GetLastError()).toLatin1().constData());
177         return false;
178     }
179
180     m_lock_mode = QtLockedFile::NoLock;
181     return true;
182 }
183
184 QtLockedFile::~QtLockedFile()
185 {
186     if (isOpen())
187         unlock();
188     if (m_mutex_hnd != 0) {
189         DWORD ret = CloseHandle(m_mutex_hnd);
190         if (ret == 0) {
191             qWarning("QtLockedFile::~QtLockedFile(): CloseHandle (mutex): %s",
192                         errorCodeToString(GetLastError()).toLatin1().constData());
193         }
194         m_mutex_hnd = 0;
195     }
196     if (m_semaphore_hnd != 0) {
197         DWORD ret = CloseHandle(m_semaphore_hnd);
198         if (ret == 0) {
199             qWarning("QtLockedFile::~QtLockedFile(): CloseHandle (semaphore): %s",
200                         errorCodeToString(GetLastError()).toLatin1().constData());
201         }
202         m_semaphore_hnd = 0;
203     }
204 }
205
206 } // namespace SharedTools