annotate 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
rev   line source
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