2 Copyright (C) 1999-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "pbd/error.h"
24 #include "pbd/enumwriter.h"
25 #include "pbd/stacktrace.h"
26 #include "pbd/pthread_utils.h"
28 #include "ardour/debug.h"
29 #include "ardour/session_event.h"
34 using namespace ARDOUR;
37 PerThreadPool* SessionEvent::pool;
40 SessionEvent::init_event_pool ()
42 pool = new PerThreadPool;
46 SessionEvent::has_per_thread_pool ()
48 return pool->has_per_thread_pool ();
52 SessionEvent::create_per_thread_pool (const std::string& name, uint32_t nitems)
54 /* this is a per-thread call that simply creates a thread-private ptr to
55 a CrossThreadPool for use by this thread whenever events are allocated/released
56 from SessionEvent::pool()
58 pool->create_per_thread_pool (name, sizeof (SessionEvent), nitems);
61 SessionEvent::SessionEvent (Type t, Action a, samplepos_t when, samplepos_t where, double spd, bool yn, bool yn2, bool yn3)
64 , action_sample (when)
65 , target_sample (where)
68 , second_yes_or_no (yn2)
69 , third_yes_or_no (yn3)
72 DEBUG_TRACE (DEBUG::SessionEvents, string_compose ("NEW SESSION EVENT, type = %1 action = %2\n", enum_2_string (type), enum_2_string (action)));
76 SessionEvent::operator new (size_t)
78 CrossThreadPool* p = pool->per_thread_pool ();
79 SessionEvent* ev = static_cast<SessionEvent*> (p->alloc ());
80 DEBUG_TRACE (DEBUG::SessionEvents, string_compose ("%1 Allocating SessionEvent from %2 ev @ %3 pool size %4 free %5 used %6\n", pthread_name(), p->name(), ev,
81 p->total(), p->available(), p->used()));
88 SessionEvent::operator delete (void *ptr, size_t /*size*/)
90 Pool* p = pool->per_thread_pool (false);
91 SessionEvent* ev = static_cast<SessionEvent*> (ptr);
93 DEBUG_TRACE (DEBUG::SessionEvents, string_compose (
94 "%1 Deleting SessionEvent @ %2 type %3 action %4 ev thread pool = %5 ev pool = %6 size %7 free %8 used %9\n",
95 pthread_name(), ev, enum_2_string (ev->type), enum_2_string (ev->action), p->name(), ev->own_pool->name(), ev->own_pool->total(), ev->own_pool->available(), ev->own_pool->used()
98 if (p && p == ev->own_pool) {
101 assert(ev->own_pool);
102 ev->own_pool->push (ev);
103 DEBUG_TRACE (DEBUG::SessionEvents, string_compose ("%1 was wrong thread for this pool, pushed event onto pending list, will be deleted on next alloc from %2 pool size %3 free %4 used %5 pending %6\n",
104 pthread_name(), ev->own_pool->name(),
105 ev->own_pool->total(), ev->own_pool->available(), ev->own_pool->used(),
106 ev->own_pool->pending_size()));
111 SessionEventManager::add_event (samplepos_t sample, SessionEvent::Type type, samplepos_t target_sample)
113 SessionEvent* ev = new SessionEvent (type, SessionEvent::Add, sample, target_sample, 0);
118 SessionEventManager::remove_event (samplepos_t sample, SessionEvent::Type type)
120 SessionEvent* ev = new SessionEvent (type, SessionEvent::Remove, sample, 0, 0);
125 SessionEventManager::replace_event (SessionEvent::Type type, samplepos_t sample, samplepos_t target)
127 SessionEvent* ev = new SessionEvent (type, SessionEvent::Replace, sample, target, 0);
132 SessionEventManager::clear_events (SessionEvent::Type type)
134 SessionEvent* ev = new SessionEvent (type, SessionEvent::Clear, SessionEvent::Immediate, 0, 0);
139 SessionEventManager::clear_events (SessionEvent::Type type, boost::function<void (void)> after)
141 SessionEvent* ev = new SessionEvent (type, SessionEvent::Clear, SessionEvent::Immediate, 0, 0);
144 /* in the calling thread, after the clear is complete, arrange to flush things from the event
145 pool pending list (i.e. to make sure they are really back in the free list and available
149 ev->event_loop = PBD::EventLoop::get_event_loop_for_thread ();
150 if (ev->event_loop) {
151 ev->rt_return = boost::bind (&CrossThreadPool::flush_pending_with_ev, ev->event_pool(), _1);
158 SessionEventManager::dump_events () const
160 cerr << "EVENT DUMP" << endl;
161 for (Events::const_iterator i = events.begin(); i != events.end(); ++i) {
163 cerr << "\tat " << (*i)->action_sample << ' ' << enum_2_string ((*i)->type) << " target = " << (*i)->target_sample << endl;
165 cerr << "Next event: ";
167 if ((Events::const_iterator) next_event == events.end()) {
168 cerr << "none" << endl;
170 cerr << "at " << (*next_event)->action_sample << ' '
171 << enum_2_string ((*next_event)->type) << " target = "
172 << (*next_event)->target_sample << endl;
174 cerr << "Immediate events pending:\n";
175 for (Events::const_iterator i = immediate_events.begin(); i != immediate_events.end(); ++i) {
176 cerr << "\tat " << (*i)->action_sample << ' ' << enum_2_string((*i)->type) << " target = " << (*i)->target_sample << endl;
178 cerr << "END EVENT_DUMP" << endl;
182 SessionEventManager::merge_event (SessionEvent* ev)
184 switch (ev->action) {
185 case SessionEvent::Remove:
190 case SessionEvent::Replace:
194 case SessionEvent::Clear:
195 _clear_event_type (ev->type);
196 /* run any additional realtime callback, if any */
200 if (ev->event_loop) {
201 /* run non-realtime callback (in some other thread) */
202 ev->event_loop->call_slot (MISSING_INVALIDATOR, boost::bind (ev->rt_return, ev));
208 case SessionEvent::Add:
212 /* try to handle immediate events right here */
214 if (ev->type == SessionEvent::Locate || ev->type == SessionEvent::LocateRoll) {
215 /* remove any existing Locates that are waiting to execute */
216 _clear_event_type (ev->type);
219 if (ev->action_sample == SessionEvent::Immediate) {
225 case SessionEvent::AutoLoop:
226 case SessionEvent::StopOnce:
227 _clear_event_type (ev->type);
230 for (Events::iterator i = events.begin(); i != events.end(); ++i) {
231 if ((*i)->type == ev->type && (*i)->action_sample == ev->action_sample) {
232 error << string_compose(_("Session: cannot have two events of type %1 at the same sample (%2)."),
233 enum_2_string (ev->type), ev->action_sample) << endmsg;
239 events.insert (events.begin(), ev);
240 events.sort (SessionEvent::compare);
241 next_event = events.begin();
245 /** @return true when @a ev is deleted. */
247 SessionEventManager::_replace_event (SessionEvent* ev)
252 /* private, used only for events that can only exist once in the queue */
254 for (i = events.begin(); i != events.end(); ++i) {
255 if ((*i)->type == ev->type) {
256 (*i)->action_sample = ev->action_sample;
257 (*i)->target_sample = ev->target_sample;
266 if (i == events.end()) {
267 events.insert (events.begin(), ev);
270 events.sort (SessionEvent::compare);
271 next_event = events.end();
277 /** @return true when @a ev is deleted. */
279 SessionEventManager::_remove_event (SessionEvent* ev)
284 for (i = events.begin(); i != events.end(); ++i) {
285 if ((*i)->type == ev->type && (*i)->action_sample == ev->action_sample) {
291 if (i == next_event) {
294 i = events.erase (i);
299 if (i != events.end()) {
307 SessionEventManager::_clear_event_type (SessionEvent::Type type)
309 Events::iterator i, tmp;
311 for (i = events.begin(); i != events.end(); ) {
316 if ((*i)->type == type) {
318 if (i == next_event) {
327 for (i = immediate_events.begin(); i != immediate_events.end(); ) {
332 if ((*i)->type == type) {
334 immediate_events.erase (i);