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, framepos_t when, framepos_t where, double spd, bool yn, bool yn2, bool yn3)
65 , target_frame (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 (framepos_t frame, SessionEvent::Type type, framepos_t target_frame)
113 SessionEvent* ev = new SessionEvent (type, SessionEvent::Add, frame, target_frame, 0);
118 SessionEventManager::remove_event (framepos_t frame, SessionEvent::Type type)
120 SessionEvent* ev = new SessionEvent (type, SessionEvent::Remove, frame, 0, 0);
125 SessionEventManager::replace_event (SessionEvent::Type type, framepos_t frame, framepos_t target)
127 SessionEvent* ev = new SessionEvent (type, SessionEvent::Replace, frame, 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_frame << ' ' << enum_2_string ((*i)->type) << " target = " << (*i)->target_frame << endl;
165 cerr << "Next event: ";
167 if ((Events::const_iterator) next_event == events.end()) {
168 cerr << "none" << endl;
170 cerr << "at " << (*next_event)->action_frame << ' '
171 << enum_2_string ((*next_event)->type) << " target = "
172 << (*next_event)->target_frame << 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_frame << ' ' << enum_2_string((*i)->type) << " target = " << (*i)->target_frame << 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->action_frame == SessionEvent::Immediate) {
220 case SessionEvent::AutoLoop:
221 case SessionEvent::AutoLoopDeclick:
222 case SessionEvent::StopOnce:
223 _clear_event_type (ev->type);
227 for (Events::iterator i = events.begin(); i != events.end(); ++i) {
228 if ((*i)->type == ev->type && (*i)->action_frame == ev->action_frame) {
229 error << string_compose(_("Session: cannot have two events of type %1 at the same frame (%2)."),
230 enum_2_string (ev->type), ev->action_frame) << endmsg;
236 events.insert (events.begin(), ev);
237 events.sort (SessionEvent::compare);
238 next_event = events.begin();
242 /** @return true when @a ev is deleted. */
244 SessionEventManager::_replace_event (SessionEvent* ev)
249 /* private, used only for events that can only exist once in the queue */
251 for (i = events.begin(); i != events.end(); ++i) {
252 if ((*i)->type == ev->type) {
253 (*i)->action_frame = ev->action_frame;
254 (*i)->target_frame = ev->target_frame;
263 if (i == events.end()) {
264 events.insert (events.begin(), ev);
267 events.sort (SessionEvent::compare);
268 next_event = events.end();
274 /** @return true when @a ev is deleted. */
276 SessionEventManager::_remove_event (SessionEvent* ev)
281 for (i = events.begin(); i != events.end(); ++i) {
282 if ((*i)->type == ev->type && (*i)->action_frame == ev->action_frame) {
288 if (i == next_event) {
291 i = events.erase (i);
296 if (i != events.end()) {
304 SessionEventManager::_clear_event_type (SessionEvent::Type type)
306 Events::iterator i, tmp;
308 for (i = events.begin(); i != events.end(); ) {
313 if ((*i)->type == type) {
315 if (i == next_event) {
324 for (i = immediate_events.begin(); i != immediate_events.end(); ) {
329 if ((*i)->type == type) {
331 immediate_events.erase (i);