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::create_per_thread_pool (const std::string& name, uint32_t nitems)
48 /* this is a per-thread call that simply creates a thread-private ptr to
49 a CrossThreadPool for use by this thread whenever events are allocated/released
50 from SessionEvent::pool()
52 pool->create_per_thread_pool (name, sizeof (SessionEvent), nitems);
55 SessionEvent::SessionEvent (Type t, Action a, framepos_t when, framepos_t where, double spd, bool yn, bool yn2, bool yn3)
59 , target_frame (where)
62 , second_yes_or_no (yn2)
63 , third_yes_or_no (yn3)
66 DEBUG_TRACE (DEBUG::SessionEvents, string_compose ("NEW SESSION EVENT, type = %1 action = %2\n", enum_2_string (type), enum_2_string (action)));
70 SessionEvent::operator new (size_t)
72 CrossThreadPool* p = pool->per_thread_pool ();
73 SessionEvent* ev = static_cast<SessionEvent*> (p->alloc ());
74 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,
75 p->total(), p->available(), p->used()));
78 if (DEBUG::SessionEvents & PBD::debug_bits) {
79 // stacktrace (cerr, 40);
87 SessionEvent::operator delete (void *ptr, size_t /*size*/)
89 Pool* p = pool->per_thread_pool ();
90 SessionEvent* ev = static_cast<SessionEvent*> (ptr);
92 DEBUG_TRACE (DEBUG::SessionEvents, string_compose (
93 "%1 Deleting SessionEvent @ %2 type %3 action %4 ev thread pool = %5 ev pool = %6 size %7 free %8 used %9\n",
94 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 (DEBUG::SessionEvents & PBD::debug_bits) {
99 // stacktrace (cerr, 40);
103 if (p == ev->own_pool) {
106 ev->own_pool->push (ev);
107 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",
108 pthread_name(), ev->own_pool->name(),
109 ev->own_pool->total(), ev->own_pool->available(), ev->own_pool->used(),
110 ev->own_pool->pending_size()));
115 SessionEventManager::add_event (framepos_t frame, SessionEvent::Type type, framepos_t target_frame)
117 SessionEvent* ev = new SessionEvent (type, SessionEvent::Add, frame, target_frame, 0);
122 SessionEventManager::remove_event (framepos_t frame, SessionEvent::Type type)
124 SessionEvent* ev = new SessionEvent (type, SessionEvent::Remove, frame, 0, 0);
129 SessionEventManager::replace_event (SessionEvent::Type type, framepos_t frame, framepos_t target)
131 SessionEvent* ev = new SessionEvent (type, SessionEvent::Replace, frame, target, 0);
136 SessionEventManager::clear_events (SessionEvent::Type type)
138 SessionEvent* ev = new SessionEvent (type, SessionEvent::Clear, SessionEvent::Immediate, 0, 0);
143 SessionEventManager::clear_events (SessionEvent::Type type, boost::function<void (void)> after)
145 SessionEvent* ev = new SessionEvent (type, SessionEvent::Clear, SessionEvent::Immediate, 0, 0);
148 /* in the calling thread, after the clear is complete, arrange to flush things from the event
149 pool pending list (i.e. to make sure they are really back in the free list and available
153 ev->event_loop = PBD::EventLoop::get_event_loop_for_thread ();
154 if (ev->event_loop) {
155 ev->rt_return = boost::bind (&CrossThreadPool::flush_pending_with_ev, ev->event_pool(), _1);
162 SessionEventManager::dump_events () const
164 cerr << "EVENT DUMP" << endl;
165 for (Events::const_iterator i = events.begin(); i != events.end(); ++i) {
167 cerr << "\tat " << (*i)->action_frame << ' ' << enum_2_string ((*i)->type) << " target = " << (*i)->target_frame << endl;
169 cerr << "Next event: ";
171 if ((Events::const_iterator) next_event == events.end()) {
172 cerr << "none" << endl;
174 cerr << "at " << (*next_event)->action_frame << ' '
175 << enum_2_string ((*next_event)->type) << " target = "
176 << (*next_event)->target_frame << endl;
178 cerr << "Immediate events pending:\n";
179 for (Events::const_iterator i = immediate_events.begin(); i != immediate_events.end(); ++i) {
180 cerr << "\tat " << (*i)->action_frame << ' ' << enum_2_string((*i)->type) << " target = " << (*i)->target_frame << endl;
182 cerr << "END EVENT_DUMP" << endl;
186 SessionEventManager::merge_event (SessionEvent* ev)
188 switch (ev->action) {
189 case SessionEvent::Remove:
194 case SessionEvent::Replace:
198 case SessionEvent::Clear:
199 _clear_event_type (ev->type);
200 /* run any additional realtime callback, if any */
204 if (ev->event_loop) {
205 /* run non-realtime callback (in some other thread) */
206 ev->event_loop->call_slot (MISSING_INVALIDATOR, boost::bind (ev->rt_return, ev));
212 case SessionEvent::Add:
216 /* try to handle immediate events right here */
218 if (ev->action_frame == SessionEvent::Immediate) {
224 case SessionEvent::AutoLoop:
225 case SessionEvent::AutoLoopDeclick:
226 case SessionEvent::StopOnce:
227 _clear_event_type (ev->type);
231 for (Events::iterator i = events.begin(); i != events.end(); ++i) {
232 if ((*i)->type == ev->type && (*i)->action_frame == ev->action_frame) {
233 error << string_compose(_("Session: cannot have two events of type %1 at the same frame (%2)."),
234 enum_2_string (ev->type), ev->action_frame) << endmsg;
240 events.insert (events.begin(), ev);
241 events.sort (SessionEvent::compare);
242 next_event = events.begin();
246 /** @return true when @a ev is deleted. */
248 SessionEventManager::_replace_event (SessionEvent* ev)
253 /* private, used only for events that can only exist once in the queue */
255 for (i = events.begin(); i != events.end(); ++i) {
256 if ((*i)->type == ev->type) {
257 (*i)->action_frame = ev->action_frame;
258 (*i)->target_frame = ev->target_frame;
267 if (i == events.end()) {
268 events.insert (events.begin(), ev);
271 events.sort (SessionEvent::compare);
272 next_event = events.end();
278 /** @return true when @a ev is deleted. */
280 SessionEventManager::_remove_event (SessionEvent* ev)
285 for (i = events.begin(); i != events.end(); ++i) {
286 if ((*i)->type == ev->type && (*i)->action_frame == ev->action_frame) {
292 if (i == next_event) {
295 i = events.erase (i);
300 if (i != events.end()) {
308 SessionEventManager::_clear_event_type (SessionEvent::Type type)
310 Events::iterator i, tmp;
312 for (i = events.begin(); i != events.end(); ) {
317 if ((*i)->type == type) {
319 if (i == next_event) {
328 for (i = immediate_events.begin(); i != immediate_events.end(); ) {
333 if ((*i)->type == type) {
335 immediate_events.erase (i);