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()));
82 SessionEvent::operator delete (void *ptr, size_t /*size*/)
84 Pool* p = pool->per_thread_pool (false);
85 SessionEvent* ev = static_cast<SessionEvent*> (ptr);
87 DEBUG_TRACE (DEBUG::SessionEvents, string_compose (
88 "%1 Deleting SessionEvent @ %2 type %3 action %4 ev thread pool = %5 ev pool = %6 size %7 free %8 used %9\n",
89 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()
92 if (p && p == ev->own_pool) {
96 ev->own_pool->push (ev);
97 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",
98 pthread_name(), ev->own_pool->name(),
99 ev->own_pool->total(), ev->own_pool->available(), ev->own_pool->used(),
100 ev->own_pool->pending_size()));
105 SessionEventManager::add_event (framepos_t frame, SessionEvent::Type type, framepos_t target_frame)
107 SessionEvent* ev = new SessionEvent (type, SessionEvent::Add, frame, target_frame, 0);
112 SessionEventManager::remove_event (framepos_t frame, SessionEvent::Type type)
114 SessionEvent* ev = new SessionEvent (type, SessionEvent::Remove, frame, 0, 0);
119 SessionEventManager::replace_event (SessionEvent::Type type, framepos_t frame, framepos_t target)
121 SessionEvent* ev = new SessionEvent (type, SessionEvent::Replace, frame, target, 0);
126 SessionEventManager::clear_events (SessionEvent::Type type)
128 SessionEvent* ev = new SessionEvent (type, SessionEvent::Clear, SessionEvent::Immediate, 0, 0);
133 SessionEventManager::clear_events (SessionEvent::Type type, boost::function<void (void)> after)
135 SessionEvent* ev = new SessionEvent (type, SessionEvent::Clear, SessionEvent::Immediate, 0, 0);
138 /* in the calling thread, after the clear is complete, arrange to flush things from the event
139 pool pending list (i.e. to make sure they are really back in the free list and available
143 ev->event_loop = PBD::EventLoop::get_event_loop_for_thread ();
144 if (ev->event_loop) {
145 ev->rt_return = boost::bind (&CrossThreadPool::flush_pending_with_ev, ev->event_pool(), _1);
152 SessionEventManager::dump_events () const
154 cerr << "EVENT DUMP" << endl;
155 for (Events::const_iterator i = events.begin(); i != events.end(); ++i) {
157 cerr << "\tat " << (*i)->action_frame << ' ' << enum_2_string ((*i)->type) << " target = " << (*i)->target_frame << endl;
159 cerr << "Next event: ";
161 if ((Events::const_iterator) next_event == events.end()) {
162 cerr << "none" << endl;
164 cerr << "at " << (*next_event)->action_frame << ' '
165 << enum_2_string ((*next_event)->type) << " target = "
166 << (*next_event)->target_frame << endl;
168 cerr << "Immediate events pending:\n";
169 for (Events::const_iterator i = immediate_events.begin(); i != immediate_events.end(); ++i) {
170 cerr << "\tat " << (*i)->action_frame << ' ' << enum_2_string((*i)->type) << " target = " << (*i)->target_frame << endl;
172 cerr << "END EVENT_DUMP" << endl;
176 SessionEventManager::merge_event (SessionEvent* ev)
178 switch (ev->action) {
179 case SessionEvent::Remove:
184 case SessionEvent::Replace:
188 case SessionEvent::Clear:
189 _clear_event_type (ev->type);
190 /* run any additional realtime callback, if any */
194 if (ev->event_loop) {
195 /* run non-realtime callback (in some other thread) */
196 ev->event_loop->call_slot (MISSING_INVALIDATOR, boost::bind (ev->rt_return, ev));
202 case SessionEvent::Add:
206 /* try to handle immediate events right here */
208 if (ev->action_frame == SessionEvent::Immediate) {
214 case SessionEvent::AutoLoop:
215 case SessionEvent::AutoLoopDeclick:
216 case SessionEvent::StopOnce:
217 _clear_event_type (ev->type);
221 for (Events::iterator i = events.begin(); i != events.end(); ++i) {
222 if ((*i)->type == ev->type && (*i)->action_frame == ev->action_frame) {
223 error << string_compose(_("Session: cannot have two events of type %1 at the same frame (%2)."),
224 enum_2_string (ev->type), ev->action_frame) << endmsg;
230 events.insert (events.begin(), ev);
231 events.sort (SessionEvent::compare);
232 next_event = events.begin();
236 /** @return true when @a ev is deleted. */
238 SessionEventManager::_replace_event (SessionEvent* ev)
243 /* private, used only for events that can only exist once in the queue */
245 for (i = events.begin(); i != events.end(); ++i) {
246 if ((*i)->type == ev->type) {
247 (*i)->action_frame = ev->action_frame;
248 (*i)->target_frame = ev->target_frame;
257 if (i == events.end()) {
258 events.insert (events.begin(), ev);
261 events.sort (SessionEvent::compare);
262 next_event = events.end();
268 /** @return true when @a ev is deleted. */
270 SessionEventManager::_remove_event (SessionEvent* ev)
275 for (i = events.begin(); i != events.end(); ++i) {
276 if ((*i)->type == ev->type && (*i)->action_frame == ev->action_frame) {
282 if (i == next_event) {
285 i = events.erase (i);
290 if (i != events.end()) {
298 SessionEventManager::_clear_event_type (SessionEvent::Type type)
300 Events::iterator i, tmp;
302 for (i = events.begin(); i != events.end(); ) {
307 if ((*i)->type == type) {
309 if (i == next_event) {
318 for (i = immediate_events.begin(); i != immediate_events.end(); ) {
323 if ((*i)->type == type) {
325 immediate_events.erase (i);