Add debug-msg for port-handle registration
[ardour.git] / libs / pbd / base_ui.cc
1 /*
2     Copyright (C) 2000-2007 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
20 #include <cstring>
21 #include <stdint.h>
22 #ifdef COMPILER_MSVC
23 #include <io.h>      // Microsoft's nearest equivalent to <unistd.h>
24 #else
25 #include <unistd.h>
26 #endif
27 #include <fcntl.h>
28 #include <cerrno>
29 #include <cstring>
30
31 #include <pthread.h>
32 #include <sched.h>
33
34 #include "pbd/base_ui.h"
35 #include "pbd/debug.h"
36 #include "pbd/pthread_utils.h"
37 #include "pbd/error.h"
38 #include "pbd/compose.h"
39 #include "pbd/failed_constructor.h"
40
41 #include "pbd/i18n.h"
42
43 #include "pbd/debug.h"
44
45 using namespace std;
46 using namespace PBD;
47 using namespace Glib;
48
49 uint64_t BaseUI::rt_bit = 1;
50 BaseUI::RequestType BaseUI::CallSlot = BaseUI::new_request_type();
51 BaseUI::RequestType BaseUI::Quit = BaseUI::new_request_type();
52
53 BaseUI::BaseUI (const string& loop_name)
54         : EventLoop (loop_name)
55         , m_context(MainContext::get_default())
56         , run_loop_thread (0)
57         , request_channel (true)
58 {
59         base_ui_instance = this;
60         request_channel.set_receive_handler (sigc::mem_fun (*this, &BaseUI::request_handler));
61
62         /* derived class must set _ok */
63 }
64
65 BaseUI::~BaseUI()
66 {
67 }
68
69 BaseUI::RequestType
70 BaseUI::new_request_type ()
71 {
72         RequestType rt;
73
74         /* XXX catch out-of-range */
75
76         rt = RequestType (rt_bit);
77         rt_bit <<= 1;
78
79         return rt;
80 }
81
82 int
83 BaseUI::set_thread_priority (const int policy, int priority) const
84 {
85         struct sched_param param;
86         memset (&param, 0, sizeof (param));
87
88         /* POSIX requires a spread of at least 32 steps between min..max */
89         const int p_min = sched_get_priority_min (policy); // Linux: 1
90         const int p_max = sched_get_priority_max (policy); // Linux: 99
91
92         if (priority == 0) {
93                 /* use default. XXX this should be relative to audio (JACK) thread,
94                  * internal backends use -20 (Audio), -21 (MIDI), -22 (compuation)
95                  */
96                 priority = 7;
97         }
98
99         if (priority > 0) {
100                 priority += p_min;
101         } else {
102                 priority += p_max;
103         }
104         if (priority > p_max) priority = p_max;
105         if (priority < p_min) priority = p_min;
106         param.sched_priority = priority;
107
108         return pthread_setschedparam (pthread_self(), SCHED_FIFO, &param);
109 }
110
111 void
112 BaseUI::main_thread ()
113 {
114         DEBUG_TRACE (DEBUG::EventLoop, string_compose ("%1: event loop running in thread %2\n", event_loop_name(), pthread_name()));
115         set_event_loop_for_thread (this);
116         thread_init ();
117         _main_loop->get_context()->signal_idle().connect (sigc::mem_fun (*this, &BaseUI::signal_running));
118         _main_loop->run ();
119 }
120
121 bool
122 BaseUI::signal_running ()
123 {
124         Glib::Threads::Mutex::Lock lm (_run_lock);
125         _running.signal ();
126
127         return false; // don't call it again
128 }
129
130 void
131 BaseUI::run ()
132 {
133         /* to be called by UI's that need/want their own distinct, self-created event loop thread.
134         */
135
136         m_context = MainContext::create();
137         _main_loop = MainLoop::create (m_context);
138         attach_request_source ();
139
140         Glib::Threads::Mutex::Lock lm (_run_lock);
141         run_loop_thread = Glib::Threads::Thread::create (mem_fun (*this, &BaseUI::main_thread));
142         _running.wait (_run_lock);
143 }
144
145 void
146 BaseUI::quit ()
147 {
148         if (_main_loop && _main_loop->is_running()) {
149                 _main_loop->quit ();
150                 run_loop_thread->join ();
151         }
152 }
153
154 bool
155 BaseUI::request_handler (Glib::IOCondition ioc)
156 {
157         /* check the request pipe */
158
159         if (ioc & ~IO_IN) {
160                 _main_loop->quit ();
161         }
162
163         if (ioc & IO_IN) {
164                 request_channel.drain ();
165
166                 /* there may been an error. we'd rather handle requests first,
167                    and then get IO_HUP or IO_ERR on the next loop.
168                 */
169
170                 /* handle requests */
171
172                 DEBUG_TRACE (DEBUG::EventLoop, string_compose ("%1: request handler\n", event_loop_name()));
173                 handle_ui_requests ();
174         }
175
176         return true;
177 }
178
179 void
180 BaseUI::signal_new_request ()
181 {
182         DEBUG_TRACE (DEBUG::EventLoop, string_compose ("%1: signal_new_request\n", event_loop_name()));
183         request_channel.wakeup ();
184 }
185
186 /**
187  * This method relies on the caller having already set m_context
188  */
189 void
190 BaseUI::attach_request_source ()
191 {
192         DEBUG_TRACE (DEBUG::EventLoop, string_compose ("%1: attach request source\n", event_loop_name()));
193         request_channel.attach (m_context);
194 }