comparison base/FileReadThread.cpp @ 95:040a151d0897

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