Chris@95
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@95
|
2
|
Chris@95
|
3 /*
|
Chris@95
|
4 Sonic Visualiser
|
Chris@95
|
5 An audio file viewer and annotation editor.
|
Chris@95
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@95
|
7 This file copyright 2006 Chris Cannam.
|
Chris@95
|
8
|
Chris@95
|
9 This program is free software; you can redistribute it and/or
|
Chris@95
|
10 modify it under the terms of the GNU General Public License as
|
Chris@95
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@95
|
12 License, or (at your option) any later version. See the file
|
Chris@95
|
13 COPYING included with this distribution for more information.
|
Chris@95
|
14 */
|
Chris@95
|
15
|
Chris@95
|
16 #include "FileReadThread.h"
|
Chris@95
|
17
|
Chris@95
|
18 #include <iostream>
|
Chris@95
|
19
|
Chris@95
|
20 FileReadThread::FileReadThread() :
|
Chris@95
|
21 m_nextToken(0),
|
Chris@95
|
22 m_exiting(false)
|
Chris@95
|
23 {
|
Chris@95
|
24 }
|
Chris@95
|
25
|
Chris@95
|
26 void
|
Chris@95
|
27 FileReadThread::run()
|
Chris@95
|
28 {
|
Chris@95
|
29 m_mutex.lock();
|
Chris@95
|
30
|
Chris@95
|
31 while (!m_exiting) {
|
Chris@95
|
32 if (m_queue.empty()) {
|
Chris@95
|
33 m_condition.wait(&m_mutex, 1000);
|
Chris@95
|
34 } else {
|
Chris@95
|
35 process();
|
Chris@95
|
36 notifyCancelled();
|
Chris@95
|
37 }
|
Chris@95
|
38 }
|
Chris@95
|
39
|
Chris@95
|
40 notifyCancelled();
|
Chris@95
|
41 m_mutex.unlock();
|
Chris@95
|
42
|
Chris@95
|
43 std::cerr << "FileReadThread::run() exiting" << std::endl;
|
Chris@95
|
44 }
|
Chris@95
|
45
|
Chris@95
|
46 void
|
Chris@95
|
47 FileReadThread::finish()
|
Chris@95
|
48 {
|
Chris@95
|
49 std::cerr << "FileReadThread::finish()" << std::endl;
|
Chris@95
|
50
|
Chris@95
|
51 m_mutex.lock();
|
Chris@95
|
52 while (!m_queue.empty()) {
|
Chris@95
|
53 m_cancelledRequests[m_queue.begin()->first] = m_queue.begin()->second;
|
Chris@95
|
54 m_newlyCancelled.insert(m_queue.begin()->first);
|
Chris@95
|
55 m_queue.erase(m_queue.begin());
|
Chris@95
|
56 }
|
Chris@95
|
57
|
Chris@95
|
58 m_exiting = true;
|
Chris@95
|
59 m_mutex.unlock();
|
Chris@95
|
60
|
Chris@95
|
61 m_condition.wakeAll();
|
Chris@95
|
62
|
Chris@95
|
63 std::cerr << "FileReadThread::finish() exiting" << std::endl;
|
Chris@95
|
64 }
|
Chris@95
|
65
|
Chris@95
|
66 int
|
Chris@95
|
67 FileReadThread::request(const Request &request)
|
Chris@95
|
68 {
|
Chris@95
|
69 m_mutex.lock();
|
Chris@95
|
70
|
Chris@95
|
71 int token = m_nextToken++;
|
Chris@95
|
72 m_queue[token] = request;
|
Chris@95
|
73
|
Chris@95
|
74 m_mutex.unlock();
|
Chris@95
|
75 m_condition.wakeAll();
|
Chris@95
|
76
|
Chris@95
|
77 return token;
|
Chris@95
|
78 }
|
Chris@95
|
79
|
Chris@95
|
80 void
|
Chris@95
|
81 FileReadThread::cancel(int token)
|
Chris@95
|
82 {
|
Chris@95
|
83 m_mutex.lock();
|
Chris@95
|
84
|
Chris@95
|
85 if (m_queue.find(token) != m_queue.end()) {
|
Chris@95
|
86 m_cancelledRequests[token] = m_queue[token];
|
Chris@95
|
87 m_queue.erase(token);
|
Chris@95
|
88 m_newlyCancelled.insert(token);
|
Chris@95
|
89 }
|
Chris@95
|
90
|
Chris@95
|
91 m_mutex.unlock();
|
Chris@95
|
92 }
|
Chris@95
|
93
|
Chris@95
|
94 bool
|
Chris@95
|
95 FileReadThread::isReady(int token)
|
Chris@95
|
96 {
|
Chris@95
|
97 m_mutex.lock();
|
Chris@95
|
98
|
Chris@95
|
99 bool ready = m_readyRequests.find(token) != m_readyRequests.end();
|
Chris@95
|
100
|
Chris@95
|
101 m_mutex.unlock();
|
Chris@95
|
102 return ready;
|
Chris@95
|
103 }
|
Chris@95
|
104
|
Chris@95
|
105 bool
|
Chris@95
|
106 FileReadThread::isCancelled(int token)
|
Chris@95
|
107 {
|
Chris@95
|
108 m_mutex.lock();
|
Chris@95
|
109
|
Chris@95
|
110 bool cancelled =
|
Chris@95
|
111 m_cancelledRequests.find(token) != m_cancelledRequests.end() &&
|
Chris@95
|
112 m_newlyCancelled.find(token) == m_newlyCancelled.end();
|
Chris@95
|
113
|
Chris@95
|
114 m_mutex.unlock();
|
Chris@95
|
115 return cancelled;
|
Chris@95
|
116 }
|
Chris@95
|
117
|
Chris@95
|
118 bool
|
Chris@95
|
119 FileReadThread::getRequest(int token, Request &request)
|
Chris@95
|
120 {
|
Chris@95
|
121 m_mutex.lock();
|
Chris@95
|
122
|
Chris@95
|
123 bool found = false;
|
Chris@95
|
124
|
Chris@95
|
125 if (m_queue.find(token) != m_queue.end()) {
|
Chris@95
|
126 request = m_queue[token];
|
Chris@95
|
127 found = true;
|
Chris@95
|
128 } else if (m_cancelledRequests.find(token) != m_cancelledRequests.end()) {
|
Chris@95
|
129 request = m_cancelledRequests[token];
|
Chris@95
|
130 found = true;
|
Chris@95
|
131 } else if (m_readyRequests.find(token) != m_readyRequests.end()) {
|
Chris@95
|
132 request = m_readyRequests[token];
|
Chris@95
|
133 found = true;
|
Chris@95
|
134 }
|
Chris@95
|
135
|
Chris@95
|
136 m_mutex.unlock();
|
Chris@95
|
137
|
Chris@95
|
138 return found;
|
Chris@95
|
139 }
|
Chris@95
|
140
|
Chris@95
|
141 void
|
Chris@95
|
142 FileReadThread::done(int token)
|
Chris@95
|
143 {
|
Chris@95
|
144 m_mutex.lock();
|
Chris@95
|
145
|
Chris@95
|
146 bool found = false;
|
Chris@95
|
147
|
Chris@95
|
148 if (m_cancelledRequests.find(token) != m_cancelledRequests.end()) {
|
Chris@95
|
149 m_cancelledRequests.erase(token);
|
Chris@95
|
150 m_newlyCancelled.erase(token);
|
Chris@95
|
151 found = true;
|
Chris@95
|
152 } else if (m_readyRequests.find(token) != m_readyRequests.end()) {
|
Chris@95
|
153 m_readyRequests.erase(token);
|
Chris@95
|
154 found = true;
|
Chris@95
|
155 } else if (m_queue.find(token) != m_queue.end()) {
|
Chris@95
|
156 std::cerr << "WARNING: FileReadThread::done(" << token << "): request is still in queue (wait or cancel it)" << std::endl;
|
Chris@95
|
157 }
|
Chris@95
|
158
|
Chris@95
|
159 m_mutex.unlock();
|
Chris@95
|
160
|
Chris@95
|
161 if (!found) {
|
Chris@95
|
162 std::cerr << "WARNING: FileReadThread::done(" << token << "): request not found" << std::endl;
|
Chris@95
|
163 }
|
Chris@95
|
164 }
|
Chris@95
|
165
|
Chris@95
|
166 void
|
Chris@95
|
167 FileReadThread::process()
|
Chris@95
|
168 {
|
Chris@95
|
169 // entered with m_mutex locked and m_queue non-empty
|
Chris@95
|
170
|
Chris@95
|
171 int token = m_queue.begin()->first;
|
Chris@95
|
172 Request request = m_queue.begin()->second;
|
Chris@95
|
173
|
Chris@95
|
174 m_mutex.unlock();
|
Chris@95
|
175
|
Chris@95
|
176 std::cerr << "FileReadThread::process: got something to do" << std::endl;
|
Chris@95
|
177
|
Chris@95
|
178 bool successful = false;
|
Chris@95
|
179 bool seekFailed = false;
|
Chris@95
|
180 ssize_t r = 0;
|
Chris@95
|
181
|
Chris@95
|
182 if (request.mutex) request.mutex->lock();
|
Chris@95
|
183
|
Chris@95
|
184 if (::lseek(request.fd, request.start, SEEK_SET) == (off_t)-1) {
|
Chris@95
|
185 seekFailed = true;
|
Chris@95
|
186 } else {
|
Chris@95
|
187 r = ::read(request.fd, request.data, request.size);
|
Chris@95
|
188 }
|
Chris@95
|
189
|
Chris@95
|
190 if (request.mutex) request.mutex->unlock();
|
Chris@95
|
191
|
Chris@95
|
192 if (seekFailed) {
|
Chris@95
|
193 ::perror("Seek failed");
|
Chris@95
|
194 std::cerr << "ERROR: FileReadThread::process: seek to "
|
Chris@95
|
195 << request.start << " failed" << std::endl;
|
Chris@95
|
196 request.size = 0;
|
Chris@95
|
197 } else {
|
Chris@95
|
198 if (r < 0) {
|
Chris@95
|
199 ::perror("ERROR: FileReadThread::process: Read failed");
|
Chris@95
|
200 request.size = 0;
|
Chris@95
|
201 } else if (r < ssize_t(request.size)) {
|
Chris@95
|
202 std::cerr << "WARNING: FileReadThread::process: read "
|
Chris@95
|
203 << request.size << " returned only " << r << " bytes"
|
Chris@95
|
204 << std::endl;
|
Chris@95
|
205 request.size = r;
|
Chris@95
|
206 } else {
|
Chris@95
|
207 successful = true;
|
Chris@95
|
208 }
|
Chris@95
|
209 }
|
Chris@95
|
210
|
Chris@95
|
211 // Check that the token hasn't been cancelled and the thread
|
Chris@95
|
212 // hasn't been asked to finish
|
Chris@95
|
213
|
Chris@95
|
214 m_mutex.lock();
|
Chris@95
|
215
|
Chris@95
|
216 if (m_queue.find(token) != m_queue.end() && !m_exiting) {
|
Chris@95
|
217 m_queue.erase(token);
|
Chris@95
|
218 m_readyRequests[token] = request;
|
Chris@95
|
219 m_mutex.unlock();
|
Chris@95
|
220 std::cerr << "emitting" << std::endl;
|
Chris@95
|
221 emit ready(token, successful);
|
Chris@95
|
222 m_mutex.lock();
|
Chris@95
|
223 }
|
Chris@95
|
224 }
|
Chris@95
|
225
|
Chris@95
|
226 void
|
Chris@95
|
227 FileReadThread::notifyCancelled()
|
Chris@95
|
228 {
|
Chris@95
|
229 // entered with m_mutex locked
|
Chris@95
|
230
|
Chris@95
|
231 while (!m_newlyCancelled.empty()) {
|
Chris@95
|
232 int token = *m_newlyCancelled.begin();
|
Chris@95
|
233 m_newlyCancelled.erase(token);
|
Chris@95
|
234 emit cancelled(token);
|
Chris@95
|
235 }
|
Chris@95
|
236 }
|
Chris@95
|
237
|
Chris@95
|
238
|