ardour
worker.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2012 Paul Davis
3  Author: David Robillard
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 
20 #include <stdlib.h>
21 #include <unistd.h>
22 
23 #include "ardour/worker.h"
24 #include "pbd/error.h"
25 
26 #include <glibmm/timer.h>
27 
28 namespace ARDOUR {
29 
30 Worker::Worker(Workee* workee, uint32_t ring_size)
31  : _workee(workee)
32  , _requests(new RingBuffer<uint8_t>(ring_size))
33  , _responses(new RingBuffer<uint8_t>(ring_size))
34  , _response((uint8_t*)malloc(ring_size))
35  , _sem(0)
36  , _exit(false)
37  , _thread (Glib::Threads::Thread::create(sigc::mem_fun(*this, &Worker::run)))
38 {}
39 
41 {
42  _exit = true;
43  _sem.post();
44  _thread->join();
45 }
46 
47 bool
48 Worker::schedule(uint32_t size, const void* data)
49 {
50  if (_requests->write_space() < size + sizeof(size)) {
51  return false;
52  }
53  if (_requests->write((const uint8_t*)&size, sizeof(size)) != sizeof(size)) {
54  return false;
55  }
56  if (_requests->write((const uint8_t*)data, size) != size) {
57  return false;
58  }
59  _sem.post();
60  return true;
61 }
62 
63 bool
64 Worker::respond(uint32_t size, const void* data)
65 {
66  if (_requests->write_space() < size + sizeof(size)) {
67  return false;
68  }
69  if (_responses->write((const uint8_t*)&size, sizeof(size)) != sizeof(size)) {
70  return false;
71  }
72  if (_responses->write((const uint8_t*)data, size) != size) {
73  return false;
74  }
75  return true;
76 }
77 
78 bool
80 {
81  uint32_t read_space = rb->read_space();
82  uint32_t size;
84  rb->get_read_vector (&vec);
85  if (vec.len[0] + vec.len[1] < sizeof(size)) {
86  return false;
87  }
88  if (vec.len[0] >= sizeof(size)) {
89  memcpy (&size, vec.buf[0], sizeof (size));
90  } else {
91  memcpy (&size, vec.buf[0], vec.len[0]);
92  memcpy (&size + vec.len[0], vec.buf[1], sizeof(size) - vec.len[0]);
93  }
94  if (read_space < size+sizeof(size)) {
95  /* message from writer is yet incomplete. respond next cycle */
96  return false;
97  }
98  return true;
99 }
100 
101 void
103 {
104  uint32_t read_space = _responses->read_space();
105  uint32_t size = 0;
106  while (read_space >= sizeof(size)) {
108  /* message from writer is yet incomplete. respond next cycle */
109  return;
110  }
111  /* read and send response */
112  _responses->read((uint8_t*)&size, sizeof(size));
113  _responses->read(_response, size);
115  read_space -= sizeof(size) + size;
116  }
117 }
118 
119 void
121 {
122  void* buf = NULL;
123  size_t buf_size = 0;
124  while (true) {
125  _sem.wait();
126  if (_exit) {
127  if (buf) free(buf);
128  return;
129  }
130 
131  uint32_t size = _requests->read_space();
132  if (size < sizeof(size)) {
133  PBD::error << "Worker: no work-data on ring buffer" << endmsg;
134  continue;
135  }
137  Glib::usleep(2000);
138  if (_exit) {
139  if (buf) free(buf);
140  return;
141  }
142  }
143  if (_requests->read((uint8_t*)&size, sizeof(size)) < sizeof(size)) {
144  PBD::error << "Worker: Error reading size from request ring"
145  << endmsg;
146  continue;
147  }
148 
149  if (size > buf_size) {
150  buf = realloc(buf, size);
151  if (buf) {
152  buf_size = size;
153  } else {
154  PBD::error << "Worker: Error allocating memory"
155  << endmsg;
156  buf_size = 0; // TODO: This is probably fatal
157  }
158  }
159 
160  if (_requests->read((uint8_t*)buf, size) < size) {
161  PBD::error << "Worker: Error reading body from request ring"
162  << endmsg;
163  continue; // TODO: This is probably fatal
164  }
165 
166  _workee->work(size, buf);
167  }
168 }
169 
170 } // namespace ARDOUR
bool respond(uint32_t size, const void *data)
Definition: worker.cc:64
guint read_space() const
Definition: ringbuffer.h:97
Worker(Workee *workee, uint32_t ring_size)
Definition: worker.cc:30
void emit_responses()
Definition: worker.cc:102
Workee * _workee
Definition: worker.h:91
virtual int work_response(uint32_t size, const void *data)=0
LIBPBD_API Transmitter error
void get_read_vector(rw_vector *)
Definition: ringbuffer.h:203
guint write_space() const
Definition: ringbuffer.h:82
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
virtual int work(uint32_t size, const void *data)=0
guint read(T *dest, guint cnt)
Definition: ringbuffer.h:124
bool schedule(uint32_t size, const void *data)
Definition: worker.cc:48
void run()
Definition: worker.cc:120
RingBuffer< uint8_t > * _responses
Definition: worker.h:93
Definition: amp.h:29
RingBuffer< uint8_t > * _requests
Definition: worker.h:92
guint write(T const *src, guint cnt)
Definition: ringbuffer.h:163
Glib::Threads::Thread * _thread
Definition: worker.h:97
bool _exit
Definition: worker.h:96
uint8_t * _response
Definition: worker.h:94
PBD::Semaphore _sem
Definition: worker.h:95
bool verify_message_completeness(RingBuffer< uint8_t > *rb)
Definition: worker.cc:79