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 (false);
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 && p == ev->own_pool) {
106 assert(ev->own_pool);
107 ev->own_pool->push (ev);
108 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",
109 pthread_name(), ev->own_pool->name(),
110 ev->own_pool->total(), ev->own_pool->available(), ev->own_pool->used(),
111 ev->own_pool->pending_size()));
116 SessionEventManager::add_event (framepos_t frame, SessionEvent::Type type, framepos_t target_frame)
118 SessionEvent* ev = new SessionEvent (type, SessionEvent::Add, frame, target_frame, 0);
123 SessionEventManager::remove_event (framepos_t frame, SessionEvent::Type type)
125 SessionEvent* ev = new SessionEvent (type, SessionEvent::Remove, frame, 0, 0);
130 SessionEventManager::replace_event (SessionEvent::Type type, framepos_t frame, framepos_t target)
132 SessionEvent* ev = new SessionEvent (type, SessionEvent::Replace, frame, target, 0);
137 SessionEventManager::clear_events (SessionEvent::Type type)
139 SessionEvent* ev = new SessionEvent (type, SessionEvent::Clear, SessionEvent::Immediate, 0, 0);
144 SessionEventManager::clear_events (SessionEvent::Type type, boost::function<void (void)> after)
146 SessionEvent* ev = new SessionEvent (type, SessionEvent::Clear, SessionEvent::Immediate, 0, 0);
149 /* in the calling thread, after the clear is complete, arrange to flush things from the event
150 pool pending list (i.e. to make sure they are really back in the free list and available
154 ev->event_loop = PBD::EventLoop::get_event_loop_for_thread ();
155 if (ev->event_loop) {
156 ev->rt_return = boost::bind (&CrossThreadPool::flush_pending_with_ev, ev->event_pool(), _1);
163 SessionEventManager::dump_events () const
165 cerr << "EVENT DUMP" << endl;
166 for (Events::const_iterator i = events.begin(); i != events.end(); ++i) {
168 cerr << "\tat " << (*i)->action_frame << ' ' << enum_2_string ((*i)->type) << " target = " << (*i)->target_frame << endl;
170 cerr << "Next event: ";
172 if ((Events::const_iterator) next_event == events.end()) {
173 cerr << "none" << endl;
175 cerr << "at " << (*next_event)->action_frame << ' '
176 << enum_2_string ((*next_event)->type) << " target = "
177 << (*next_event)->target_frame << endl;
179 cerr << "Immediate events pending:\n";
180 for (Events::const_iterator i = immediate_events.begin(); i != immediate_events.end(); ++i) {
181 cerr << "\tat " << (*i)->action_frame << ' ' << enum_2_string((*i)->type) << " target = " << (*i)->target_frame << endl;
183 cerr << "END EVENT_DUMP" << endl;
187 SessionEventManager::merge_event (SessionEvent* ev)
189 switch (ev->action) {
190 case SessionEvent::Remove:
195 case SessionEvent::Replace:
199 case SessionEvent::Clear:
200 _clear_event_type (ev->type);
201 /* run any additional realtime callback, if any */
205 if (ev->event_loop) {
206 /* run non-realtime callback (in some other thread) */
207 ev->event_loop->call_slot (MISSING_INVALIDATOR, boost::bind (ev->rt_return, ev));
213 case SessionEvent::Add:
217 /* try to handle immediate events right here */
219 if (ev->action_frame == SessionEvent::Immediate) {
225 case SessionEvent::AutoLoop:
226 case SessionEvent::AutoLoopDeclick:
227 case SessionEvent::StopOnce:
228 _clear_event_type (ev->type);
232 for (Events::iterator i = events.begin(); i != events.end(); ++i) {
233 if ((*i)->type == ev->type && (*i)->action_frame == ev->action_frame) {
234 error << string_compose(_("Session: cannot have two events of type %1 at the same frame (%2)."),
235 enum_2_string (ev->type), ev->action_frame) << endmsg;
241 events.insert (events.begin(), ev);
242 events.sort (SessionEvent::compare);
243 next_event = events.begin();
247 /** @return true when @a ev is deleted. */
249 SessionEventManager::_replace_event (SessionEvent* ev)
254 /* private, used only for events that can only exist once in the queue */
256 for (i = events.begin(); i != events.end(); ++i) {
257 if ((*i)->type == ev->type) {
258 (*i)->action_frame = ev->action_frame;
259 (*i)->target_frame = ev->target_frame;
268 if (i == events.end()) {
269 events.insert (events.begin(), ev);
272 events.sort (SessionEvent::compare);
273 next_event = events.end();
279 /** @return true when @a ev is deleted. */
281 SessionEventManager::_remove_event (SessionEvent* ev)
286 for (i = events.begin(); i != events.end(); ++i) {
287 if ((*i)->type == ev->type && (*i)->action_frame == ev->action_frame) {
293 if (i == next_event) {
296 i = events.erase (i);
301 if (i != events.end()) {
309 SessionEventManager::_clear_event_type (SessionEvent::Type type)
311 Events::iterator i, tmp;
313 for (i = events.begin(); i != events.end(); ) {
318 if ((*i)->type == type) {
320 if (i == next_event) {
329 for (i = immediate_events.begin(); i != immediate_events.end(); ) {
334 if ((*i)->type == type) {
336 immediate_events.erase (i);