summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYonit Halperin <yhalperi@redhat.com>2009-11-08 16:34:12 +0200
committerYaniv Kamay <ykamay@redhat.com>2009-11-09 14:39:33 +0200
commit8d5b738ba169c44d223ab6d99ec12e763ce5bc8e (patch)
tree3c1d4dd1b3c32f9a03dd456ea921a66ed7f6c7fd
parent082934699611d5985ecf3386259d270d75e41c12 (diff)
downloadspice-8d5b738ba169c44d223ab6d99ec12e763ce5bc8e.tar.gz
spice-8d5b738ba169c44d223ab6d99ec12e763ce5bc8e.tar.xz
spice-8d5b738ba169c44d223ab6d99ec12e763ce5bc8e.zip
spice client: creating a general process loop.
The process loop is responsible for: 1) waiting for events 2) timers 3) events queue for actions that should be performed in the context of the thread and are pushed from other threads. The benefits: 1) remove duplicity: till now, there was one implementaion of events loop for the channels and another one for the main thread. 2) timers can be executed on each thread and not only on the main thread. 3) events can be pushed to each thread and not only to the main thread. In this commit, only the main thread was modified to use the new process loop.
-rw-r--r--client/Makefile.am1
-rw-r--r--client/application.cpp133
-rw-r--r--client/application.h76
-rw-r--r--client/cursor_channel.cpp22
-rw-r--r--client/display_channel.cpp15
-rw-r--r--client/event_sources.h95
-rw-r--r--client/events_loop.h12
-rw-r--r--client/inputs_channel.cpp10
-rw-r--r--client/platform.h31
-rw-r--r--client/process_loop.cpp390
-rw-r--r--client/process_loop.h233
-rw-r--r--client/red_client.cpp7
-rw-r--r--client/red_client.h2
-rw-r--r--client/screen.cpp5
-rw-r--r--client/screen_layer.cpp17
-rw-r--r--client/tunnel_channel.cpp89
-rw-r--r--client/tunnel_channel.h2
-rw-r--r--client/windows/event_sources_p.cpp209
-rw-r--r--client/windows/event_sources_p.h52
-rw-r--r--client/windows/events_loop_p.h8
-rw-r--r--client/windows/named_pipe.cpp33
-rw-r--r--client/windows/named_pipe.h20
-rw-r--r--client/windows/platform.cpp227
-rw-r--r--client/windows/redc.vcproj20
-rw-r--r--client/windows/win_platform.h16
-rw-r--r--client/x11/Makefile.am2
-rw-r--r--client/x11/event_sources_p.cpp339
-rw-r--r--client/x11/event_sources_p.h63
-rw-r--r--client/x11/events_loop_p.cpp12
-rw-r--r--client/x11/events_loop_p.h3
-rw-r--r--client/x11/named_pipe.cpp4
-rw-r--r--client/x11/named_pipe.h14
-rw-r--r--client/x11/platform.cpp330
33 files changed, 1752 insertions, 740 deletions
diff --git a/client/Makefile.am b/client/Makefile.am
index 51d4857e..2a2d076d 100644
--- a/client/Makefile.am
+++ b/client/Makefile.am
@@ -50,6 +50,7 @@ RED_COMMON_SRCS = \
pixels_source.h \
platform.h \
playback_channel.cpp \
+ process_loop.cpp \
quic.cpp \
read_write_mutex.h \
record_channel.cpp \
diff --git a/client/application.cpp b/client/application.cpp
index 65937156..3b797539 100644
--- a/client/application.cpp
+++ b/client/application.cpp
@@ -50,72 +50,35 @@
mutex_t cairo_surface_user_data_mutex;
#endif
-SyncEvent::SyncEvent()
- : _err (false)
- , _ready (false)
+void ConnectedEvent::response(AbstractProcessLoop& events_loop)
{
+ static_cast<Application*>(events_loop.get_owner())->on_connected();
}
-SyncEvent::~SyncEvent()
+void DisconnectedEvent::response(AbstractProcessLoop& events_loop)
{
-}
-
-void SyncEvent::responce(Application& application)
-{
- try {
- do_responce(application);
- } catch (Exception& e) {
- LOG_WARN("unhandle exception: %s", e.what());
- _err = true;
- } catch (...) {
- _err = true;
- }
- Lock lock(_mutex);
- _ready = true;
- _condition.notify_one();
-}
-
-void SyncEvent::wait()
-{
- //todo: process event if on main thread
- Lock lock(_mutex);
- while (!_ready) {
- _condition.wait(lock);
- }
-}
-
-void ConnectedEvent::responce(Application& application)
-{
- application.on_connected();
-}
-
-void DisconnectedEvent::responce(Application& application)
-{
- application.show_splash(0);
+ Application* app = static_cast<Application*>(events_loop.get_owner());
+ app->show_splash(0);
#ifndef RED_DEBUG
- application.quit(SPICEC_ERROR_CODE_SUCCESS);
+ app->do_quit(SPICEC_ERROR_CODE_SUCCESS);
#endif
}
-void CoonnectionError::responce(Application& application)
+void ConnectionErrorEvent::response(AbstractProcessLoop& events_loop)
{
- application.show_splash(0);
+ Application* app = static_cast<Application*>(events_loop.get_owner());
+ app->show_splash(0);
#ifndef RED_DEBUG
- application.quit(_error_code);
+ app->do_quit(_error_code);
#endif
}
-void ErrorEvent::responce(Application& application)
-{
- application.quit(SPICEC_ERROR_CODE_ERROR);
-}
-
-void MonitorsQuery::do_responce(Application& application)
+void MonitorsQuery::do_response(AbstractProcessLoop& events_loop)
{
Monitor* mon;
int i = 0;
- while ((mon = application.find_monitor(i++))) {
+ while ((mon = (static_cast<Application*>(events_loop.get_owner()))->find_monitor(i++))) {
MonitorInfo info;
info.size = mon->get_size();
info.depth = 32;
@@ -236,15 +199,14 @@ enum AppCommands {
};
Application::Application()
- : _client (*this)
+ : ProcessLoop (this)
+ , _client (*this)
, _enabled_channels (RED_CHANNEL_END, true)
, _main_screen (NULL)
- , _quitting (false)
, _active (false)
, _full_screen (false)
, _changing_screens (false)
, _exit_code (0)
- , _events_gen (0)
, _active_screen (NULL)
, _gui_layer (new GUILayer())
, _inputs_handler (&default_inputs_handler)
@@ -252,6 +214,7 @@ Application::Application()
, _title (L"SPICEc:%d")
{
DBG(0, "");
+ Platform::set_process_loop(*this);
init_monitors();
init_key_table();
@@ -325,59 +288,13 @@ void Application::remove_inputs_handler(InputsHandler& handler)
_inputs_handler = &default_inputs_handler;
}
-void Application::process_events()
-{
- _events_gen++;
- for (;;) {
- Event* event;
- Lock lock(_events_lock);
- if (_events.empty()) {
- return;
- }
- event = _events.front();
- if (event->_generation == _events_gen) {
- Platform::wakeup();
- return;
- }
- _events.pop_front();
- lock.unlock();
- event->responce(*this);
- event->unref();
- }
-}
-
-void Application::push_event(Event* event)
-{
- Lock lock(_events_lock);
- bool notify = _events.empty();
- _events.push_back(event);
- event->_generation = _events_gen;
- event->ref();
- if (notify) {
- Platform::wakeup();
- }
-}
-
-int Application::message_loop()
-{
- for (;;) {
- Platform::wait_events();
- if (Platform::process_events()) {
- _quitting = true;
- break;
- }
- process_events();
- }
- return _exit_code;
-}
-
void Application::abort()
{
Platform::set_event_listener(NULL);
Platform::set_display_mode_listner(NULL);
unpress_all();
while (!_client.abort()) {
- process_events();
+ ProcessLoop::process_events_queue();
Platform::msleep(100);
}
}
@@ -398,22 +315,10 @@ void Application::connect()
int Application::run()
{
- try {
- _client.connect();
- _exit_code = message_loop();
- } catch (...) {
- throw;
- }
- return _exit_code;
-}
+ _client.connect();
+ _exit_code = ProcessLoop::run();
+ return _exit_code;
-void Application::quit(int exit_code)
-{
- if (!_quitting) {
- _quitting = true;
- _exit_code = exit_code;
- Platform::send_quit_request();
- }
}
RedScreen* Application::find_screen(int id)
diff --git a/client/application.h b/client/application.h
index 1a14c5ed..91afb54e 100644
--- a/client/application.h
+++ b/client/application.h
@@ -25,6 +25,7 @@
#include "platform.h"
#include "menu.h"
#include "hot_keys.h"
+#include "process_loop.h"
class RedScreen;
class Application;
@@ -35,73 +36,25 @@ class Monitor;
class CmdLineParser;
class Menu;
-class Event {
-public:
- Event() : _refs (1) {}
-
- virtual void responce(Application& application) = 0;
-
- Event* ref() { ++_refs; return this;}
- void unref() {if (--_refs == 0) delete this;}
-
-protected:
- virtual ~Event() {}
-
- AtomicCount _refs;
- friend class Application;
- uint32_t _generation;
-};
-
-class SyncEvent: public Event {
-public:
- SyncEvent();
-
- void wait();
- bool success() { return !_err;}
-
- virtual void do_responce(Application& application) {}
-
-protected:
- virtual ~SyncEvent();
-
-private:
- virtual void responce(Application& application);
-
-private:
- Mutex _mutex;
- Condition _condition;
- bool _err;
- bool _ready;
-};
class ConnectedEvent: public Event {
public:
- ConnectedEvent() : Event() {}
- virtual void responce(Application& application);
+ virtual void response(AbstractProcessLoop& events_loop);
};
class DisconnectedEvent: public Event {
public:
- DisconnectedEvent() : Event() {}
- virtual void responce(Application& application);
+ virtual void response(AbstractProcessLoop& events_loop);
};
-class CoonnectionError: public Event {
+class ConnectionErrorEvent: public Event {
public:
- CoonnectionError(int error_code) : Event(), _error_code (error_code) {}
-
- virtual void responce(Application& application);
-
+ ConnectionErrorEvent(int error_code) : _error_code (error_code) {}
+ virtual void response(AbstractProcessLoop& events_loop);
private:
int _error_code;
};
-class ErrorEvent: public Event {
-public:
- ErrorEvent() : Event() {}
- virtual void responce(Application& application);
-};
-
struct MonitorInfo {
int depth;
Point size;
@@ -112,8 +65,7 @@ class MonitorsQuery: public SyncEvent {
public:
MonitorsQuery() {}
- virtual void do_responce(Application& application);
-
+ virtual void do_response(AbstractProcessLoop& events_loop);
std::vector<MonitorInfo>& get_monitors() {return _monitors;}
private:
@@ -138,7 +90,8 @@ enum CanvasOption {
#endif
};
-class Application : public Platform::EventListener,
+class Application : public ProcessLoop,
+ public Platform::EventListener,
public Platform::DisplayModeListner,
public CommandTarget {
public:
@@ -146,8 +99,7 @@ public:
virtual ~Application();
int run();
- void quit(int exit_code);
- void push_event(Event* event);
+
void set_inputs_handler(InputsHandler& handler);
void remove_inputs_handler(InputsHandler& handler);
RedScreen* find_screen(int id);
@@ -195,8 +147,6 @@ private:
bool set_enable_channels(CmdLineParser& parser, bool enable, char *val);
bool set_canvas_option(CmdLineParser& parser, char *val);
bool process_cmd_line(int argc, char** argv);
- void process_events();
- int message_loop();
void abort();
void init_scan_code(int index);
void init_korean_scan_code(int index);
@@ -234,6 +184,8 @@ private:
static void init_logger();
static void init_globals();
+ friend class DisconnectedEvent;
+ friend class ConnectionErrorEvent;
friend class MonitorsQuery;
friend class AutoAbort;
@@ -242,15 +194,11 @@ private:
PeerConnectionOptMap _peer_con_opt;
std::vector<bool> _enabled_channels;
std::vector<RedScreen*> _screens;
- std::list<Event*> _events;
RedScreen* _main_screen;
- Mutex _events_lock;
- bool _quitting;
bool _active;
bool _full_screen;
bool _changing_screens;
int _exit_code;
- uint32_t _events_gen;
RedScreen* _active_screen;
KeyInfo _key_table[REDKEY_NUM_KEYS];
HotKeys _hot_keys;
diff --git a/client/cursor_channel.cpp b/client/cursor_channel.cpp
index a78eba35..d5a64b2b 100644
--- a/client/cursor_channel.cpp
+++ b/client/cursor_channel.cpp
@@ -331,7 +331,7 @@ public:
cursor->set_opaque(native_cursor);
}
- virtual void responce(Application& application)
+ virtual void response(AbstractProcessLoop& events_loop)
{
CursorData *cursor = *_cursor;
create_cursor();
@@ -345,7 +345,8 @@ public:
_channel._cursor_rect.top = _y - cursor->header().hot_spot_y;
_channel._cursor_rect.bottom = _channel._cursor_rect.top + cursor->header().height;
- if (application.get_mouse_mode() == RED_MOUSE_MODE_CLIENT) {
+ if (static_cast<Application*>(events_loop.get_owner())->get_mouse_mode() ==
+ RED_MOUSE_MODE_CLIENT) {
RedScreen* screen = _channel.screen();
ASSERT(screen);
screen->set_cursor(_visible ? cursor : NULL);
@@ -381,10 +382,11 @@ public:
{
}
- virtual void responce(Application& application)
+ virtual void response(AbstractProcessLoop& events_loop)
{
_channel._cursor_visible = true;
- if (application.get_mouse_mode() == RED_MOUSE_MODE_CLIENT) {
+ if (static_cast<Application*>(events_loop.get_owner())->get_mouse_mode() ==
+ RED_MOUSE_MODE_CLIENT) {
RedScreen* screen = _channel.screen();
ASSERT(screen);
screen->set_cursor(_channel._cursor);
@@ -412,10 +414,11 @@ private:
class CursorHideEvent: public Event {
public:
CursorHideEvent(CursorChannel& channel): _channel (channel) {}
- virtual void responce(Application& application)
+ virtual void response(AbstractProcessLoop& events_loop)
{
_channel._cursor_visible = false;
- if (application.get_mouse_mode() == RED_MOUSE_MODE_CLIENT) {
+ if (static_cast<Application*>(events_loop.get_owner())->get_mouse_mode() ==
+ RED_MOUSE_MODE_CLIENT) {
RedScreen* screen = _channel.screen();
ASSERT(screen);
screen->set_cursor(NULL);
@@ -431,7 +434,7 @@ private:
class CursorRemoveEvent: public Event {
public:
CursorRemoveEvent(CursorChannel& channel): _channel (channel) {}
- virtual void responce(Application& application)
+ virtual void response(AbstractProcessLoop& events_loop)
{
_channel._cursor_visible = false;
_channel.clear_area();
@@ -455,13 +458,14 @@ class CursorModeEvent: public Event {
public:
CursorModeEvent(CursorChannel& channel): _channel (channel) {}
- virtual void responce(Application& application)
+ virtual void response(AbstractProcessLoop& events_loop)
{
RedScreen* screen = _channel.screen();
if (!screen) {
return;
}
- if (application.get_mouse_mode() == RED_MOUSE_MODE_CLIENT) {
+ if (static_cast<Application*>(events_loop.get_owner())->get_mouse_mode() ==
+ RED_MOUSE_MODE_CLIENT) {
_channel.clear_area();
screen->set_cursor(_channel._cursor_visible ? _channel._cursor : NULL);
} else {
diff --git a/client/display_channel.cpp b/client/display_channel.cpp
index 2e2e4f56..e9d4f192 100644
--- a/client/display_channel.cpp
+++ b/client/display_channel.cpp
@@ -54,11 +54,12 @@ public:
{
}
- virtual void do_responce(Application& application)
+ virtual void do_response(AbstractProcessLoop& events_loop)
{
+ Application* app = (Application*)events_loop.get_owner();
_channel.destroy_canvas();
_channel.screen()->set_mode(_width, _height, _depth);
- _channel.create_canvas(application.get_canvas_types(), _width, _height, _depth);
+ _channel.create_canvas(app->get_canvas_types(), _width, _height, _depth);
}
private:
@@ -75,9 +76,9 @@ public:
{
}
- virtual void responce(Application& application)
+ virtual void response(AbstractProcessLoop& events_loop)
{
- application.hide_splash(_screen_id);
+ static_cast<Application*>(events_loop.get_owner())->hide_splash(_screen_id);
}
private:
@@ -831,7 +832,7 @@ public:
ASSERT(_timer == INVALID_TIMER);
}
- virtual void do_responce(Application& application)
+ virtual void do_response(AbstractProcessLoop& events_loop)
{
if ((_timer = Platform::create_interval_timer(_proc, _user_data)) == INVALID_TIMER) {
THROW("create timer failed");
@@ -850,7 +851,7 @@ class DestroyTimerEvent: public Event {
public:
DestroyTimerEvent(TimerID timer) : _timer (timer) {}
- virtual void responce(Application& application)
+ virtual void response(AbstractProcessLoop& events_loop)
{
Platform::destroy_interval_timer(_timer);
}
@@ -866,7 +867,7 @@ public:
{
}
- virtual void responce(Application& application)
+ virtual void response(AbstractProcessLoop& events_loop)
{
_channel.activate_streams_timer();
}
diff --git a/client/event_sources.h b/client/event_sources.h
new file mode 100644
index 00000000..a7b39aee
--- /dev/null
+++ b/client/event_sources.h
@@ -0,0 +1,95 @@
+/*
+ Copyright (C) 2009 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _H_EVENT_SOURCES
+#define _H_EVENT_SOURCES
+
+#include "common.h"
+#include "event_sources_p.h"
+
+class EventSource;
+
+// TODO: the class is not thread safe
+class EventSources: public EventSources_p {
+public:
+ class Trigger;
+ class Socket;
+ class File;
+ class Handle;
+
+ EventSources();
+ virtual ~EventSources();
+
+ void add_trigger(Trigger& trigger);
+ void remove_trigger(Trigger& trigger);
+ void add_socket(Socket& socket);
+ void remove_socket(Socket& socket);
+ void add_file(File& file);
+ void remove_file(File& file);
+ void add_handle(Handle& handle);
+ void remove_handle(Handle& handle);
+
+ /* return true if the events loop should quit */
+ bool wait_events(int timeout_ms = INFINITE);
+};
+
+class EventSource {
+public:
+ virtual ~EventSource() {}
+ virtual void on_event() = 0;
+
+private:
+ virtual void action() {on_event();}
+
+ friend class EventSources;
+};
+
+class EventSources::Trigger: public EventSource, private Trigger_p {
+public:
+ Trigger();
+ virtual ~Trigger();
+ virtual void trigger();
+ virtual void reset();
+
+private:
+ virtual void action();
+
+ friend class EventSources;
+};
+
+class EventSources::Socket: public EventSource {
+protected:
+ virtual int get_socket() = 0;
+
+ friend class EventSources;
+};
+
+
+class EventSources::File: public EventSource {
+protected:
+ virtual int get_fd() = 0;
+
+ friend class EventSources;
+};
+
+class EventSources::Handle: public EventSource, public Handle_p {
+
+ friend class EventSources;
+};
+
+#endif
+
diff --git a/client/events_loop.h b/client/events_loop.h
index 50a83e1d..ac26a0e6 100644
--- a/client/events_loop.h
+++ b/client/events_loop.h
@@ -21,7 +21,7 @@
#include "common.h"
#include "events_loop_p.h"
-class EventSource;
+class EventSourceOld;
class EventsLoop: public EventsLoop_p {
public:
@@ -43,9 +43,9 @@ public:
void run_once(int timeout_milli = INFINITE);
};
-class EventSource {
+class EventSourceOld {
public:
- virtual ~EventSource() {}
+ virtual ~EventSourceOld() {}
virtual void on_event() = 0;
private:
@@ -54,7 +54,7 @@ private:
friend class EventsLoop;
};
-class EventsLoop::Trigger: public EventSource, private Trigger_p {
+class EventsLoop::Trigger: public EventSourceOld, private EventsLoop_p::Trigger_p {
public:
Trigger();
virtual ~Trigger();
@@ -67,7 +67,7 @@ private:
friend class EventsLoop;
};
-class EventsLoop::Socket: public EventSource {
+class EventsLoop::Socket: public EventSourceOld {
protected:
virtual int get_socket() = 0;
@@ -75,7 +75,7 @@ protected:
};
-class EventsLoop::File: public EventSource {
+class EventsLoop::File: public EventSourceOld {
protected:
virtual int get_fd() = 0;
diff --git a/client/inputs_channel.cpp b/client/inputs_channel.cpp
index 8035bfb3..d686be22 100644
--- a/client/inputs_channel.cpp
+++ b/client/inputs_channel.cpp
@@ -28,9 +28,9 @@ class SetInputsHandlerEvent: public Event {
public:
SetInputsHandlerEvent(InputsChannel& channel) : _channel (channel) {}
- virtual void responce(Application& application)
+ virtual void response(AbstractProcessLoop& events_loop)
{
- application.set_inputs_handler(_channel);
+ static_cast<Application*>(events_loop.get_owner())->set_inputs_handler(_channel);
}
private:
@@ -41,7 +41,7 @@ class KeyModifiersEvent: public Event {
public:
KeyModifiersEvent(InputsChannel& channel) : _channel (channel) {}
- virtual void responce(Application& application)
+ virtual void response(AbstractProcessLoop& events_loop)
{
Lock lock(_channel._update_modifiers_lock);
_channel._active_modifiers_event = false;
@@ -56,9 +56,9 @@ class RemoveInputsHandlerEvent: public SyncEvent {
public:
RemoveInputsHandlerEvent(InputsChannel& channel) : _channel (channel) {}
- virtual void do_responce(Application& application)
+ virtual void do_response(AbstractProcessLoop& events_loop)
{
- application.remove_inputs_handler(_channel);
+ static_cast<Application*>(events_loop.get_owner())->remove_inputs_handler(_channel);
}
private:
diff --git a/client/platform.h b/client/platform.h
index 0982bf63..a4310d98 100644
--- a/client/platform.h
+++ b/client/platform.h
@@ -19,12 +19,10 @@
#define _H_PLATFORM
#include "cursor.h"
+#include "process_loop.h"
+#include "event_sources.h"
#include "events_loop.h"
-#define INVALID_TIMER (~TimerID(0))
-typedef unsigned long TimerID;
-typedef void (*timer_proc_t)(void* opaque, TimerID timer);
-
class WaveRecordAbstract;
class WavePlaybackAbstract;
class Icon;
@@ -32,19 +30,19 @@ class Icon;
class Monitor;
typedef std::list<Monitor*> MonitorsList;
+/* TODO: tmp till each channel will handle its own thread
+ timers or directly through the main thread */
+#define INVALID_TIMER (~TimerID(0))
+typedef unsigned long TimerID;
+typedef void (*timer_proc_t)(void* opaque, TimerID timer);
+
+
class Platform {
public:
static void init();
- static void wait_events();
- static bool process_events();
- static void wakeup();
+ static void set_process_loop(ProcessLoop& main_process_loop);
static void msleep(unsigned int millisec);
static void yield();
- static void send_quit_request();
- static TimerID create_interval_timer(timer_proc_t proc, void* opaque);
- static bool activate_interval_timer(TimerID timer, unsigned int millisec);
- static bool deactivate_interval_timer(TimerID timer);
- static void destroy_interval_timer(TimerID timer);
static uint64_t get_monolithic_time();
static void get_temp_dir(std::string& path);
@@ -52,6 +50,8 @@ public:
static void destroy_monitors();
static bool is_monitors_pos_valid();
+ static void send_quit_request();
+
enum ThreadPriority {
PRIORITY_INVALID,
PRIORITY_TIME_CRITICAL,
@@ -98,6 +98,12 @@ public:
class DisplayModeListner;
static void set_display_mode_listner(DisplayModeListner* listener);
+ /* TODO: tmp till each channel will handle its own thread
+ timers or directly through the main thread */
+ static TimerID create_interval_timer(timer_proc_t proc, void* opaque);
+ static bool activate_interval_timer(TimerID timer, unsigned int millisec);
+ static bool deactivate_interval_timer(TimerID timer);
+ static void destroy_interval_timer(TimerID timer);
};
class Platform::EventListener {
@@ -108,6 +114,7 @@ public:
virtual void on_monitors_change() = 0;
};
+// TODO: tmp till all channels work with ProcessLoop
class Platform::RecordClinet {
public:
virtual ~RecordClinet() {}
diff --git a/client/process_loop.cpp b/client/process_loop.cpp
new file mode 100644
index 00000000..41aac43e
--- /dev/null
+++ b/client/process_loop.cpp
@@ -0,0 +1,390 @@
+/*
+ Copyright (C) 2009 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "common.h"
+#include "process_loop.h"
+#include "debug.h"
+#include "platform.h"
+#include "utils.h"
+
+SyncEvent::SyncEvent()
+ : _err (false)
+ , _ready (false)
+{
+}
+
+SyncEvent::~SyncEvent()
+{
+}
+
+void SyncEvent::response(AbstractProcessLoop& events_loop)
+{
+ try {
+ do_response(events_loop);
+ } catch (Exception& e) {
+ LOG_WARN("unhandle exception: %s", e.what());
+ _err = true;
+ } catch (...) {
+ _err = true;
+ }
+ Lock lock(_mutex);
+ _ready = true;
+ _condition.notify_one();
+}
+
+void SyncEvent::wait()
+{
+#ifdef RED_DEBUG
+ ASSERT(!_process_loop || !_process_loop->is_same_thread(pthread_self()));
+#endif
+ Lock lock(_mutex);
+ while (!_ready) {
+ _condition.wait(lock);
+ }
+}
+
+class ProcessLoop::QuitEvent: public Event {
+public:
+ QuitEvent(int error_code) : _error_code(error_code) {}
+ virtual void response(AbstractProcessLoop& events_loop);
+private:
+ int _error_code;
+};
+
+void ProcessLoop::QuitEvent::response(AbstractProcessLoop& events_loop)
+{
+ events_loop.do_quit(_error_code);
+}
+
+/* EventsQueue */
+
+EventsQueue::EventsQueue(AbstractProcessLoop& owner)
+ : _events_gen (0)
+ , _owner (owner)
+{
+}
+
+EventsQueue::~EventsQueue()
+{
+ clear_queue();
+}
+
+void EventsQueue::clear_queue()
+{
+ Lock lock(_events_lock);
+ while (!_events.empty()) {
+ Event* event = _events.front();
+ _events.pop_front();
+ event->unref();
+ }
+}
+
+int EventsQueue::push_event(Event* event)
+{
+ Lock lock(_events_lock);
+ _events.push_back(event);
+ event->_generation = _events_gen;
+ event->ref();
+#ifdef RED_DEBUG
+ event->set_process_loop(&_owner);
+#endif
+ return _events.size();
+}
+
+void EventsQueue::process_events()
+{
+ _events_gen++;
+
+ for (;;) {
+ Event* event;
+ Lock lock(_events_lock);
+ if (_events.empty()) {
+ return;
+ }
+ event = _events.front();
+ if (event->_generation == _events_gen) {
+ return;
+ }
+ _events.pop_front();
+
+ lock.unlock();
+ event->response(_owner);
+#ifdef RED_DEBUG
+ event->set_process_loop(NULL);
+#endif
+ event->unref();
+ }
+}
+
+bool EventsQueue::is_empty()
+{
+ Lock lock(_events_lock);
+ return _events.empty();
+}
+
+/* Timers Queue */
+
+Timer::Timer()
+ : _is_armed (false)
+{
+}
+
+Timer::~Timer()
+{
+}
+
+void Timer::arm(uint32_t msec)
+{
+ _interval = msec;
+ _expiration = get_now();
+ calc_next_expiration_time();
+ _is_armed = true;
+}
+
+void Timer::disarm()
+{
+ _is_armed = false;
+}
+
+uint64_t Timer::get_now()
+{
+ return (Platform::get_monolithic_time() / 1000 / 1000);
+}
+
+TimersQueue::TimersQueue(AbstractProcessLoop& owner)
+ : _owner (owner)
+{
+}
+
+TimersQueue::~TimersQueue()
+{
+ clear_queue();
+}
+
+void TimersQueue::clear_queue()
+{
+ RecurciveLock lock(_timers_lock);
+ TimersSet::iterator iter;
+ for (iter = _armed_timers.begin(); iter != _armed_timers.end(); iter++) {
+ (*iter)->disarm();
+ }
+ _armed_timers.clear();
+}
+
+void TimersQueue::activate_interval_timer(Timer* timer, unsigned int millisec)
+{
+ RecurciveLock lock(_timers_lock);
+ timer->ref();
+ deactivate_interval_timer(timer);
+ timer->arm(millisec);
+ _armed_timers.insert(timer);
+}
+
+void TimersQueue::deactivate_interval_timer(Timer* timer)
+{
+ RecurciveLock lock(_timers_lock);
+ if (timer->is_armed()) {
+#ifdef RED_DEBUG
+ int ret =
+#endif
+ _armed_timers.erase(timer);
+ ASSERT(ret);
+ timer->disarm();
+ timer->unref();
+ }
+}
+
+int TimersQueue::get_soonest_timeout()
+{
+ RecurciveLock lock(_timers_lock);
+ TimersSet::iterator iter;
+ iter = _armed_timers.begin();
+ if (iter == _armed_timers.end()) {
+ return INFINITE;
+ }
+
+ uint64_t now = Timer::get_now();
+ uint64_t next_time = (*iter)->get_expiration();
+
+ if (next_time <= now) {
+ return 0;
+ }
+ return (int)(next_time - now);
+}
+
+#define TIMER_COMPENSATION
+
+void TimersQueue::timers_action()
+{
+ RecurciveLock lock(_timers_lock);
+ uint64_t now = Timer::get_now();
+ TimersSet::iterator iter;
+
+ while (((iter = _armed_timers.begin()) != _armed_timers.end()) &&
+ ((*iter)->get_expiration() <= now)) {
+ Timer* timer = *iter;
+ _armed_timers.erase(iter);
+#ifndef TIMER_COMPENSATION
+ timer->_experatoin = now;
+#endif
+ timer->calc_next_expiration_time();
+#ifdef TIMER_COMPENSATION
+ if (timer->_expiration <= now) {
+ timer->_expiration = now;
+ timer->calc_next_expiration_time();
+ }
+#endif
+ _armed_timers.insert(timer);
+ timer->response(_owner);
+ }
+}
+
+ProcessLoop::ProcessLoop(void* owner)
+ : _events_queue (*this)
+ , _timers_queue (*this)
+ , _owner (owner)
+ , _quitting (false)
+ , _exit_code (0)
+ , _started (false)
+
+{
+ _event_sources.add_trigger(_wakeup_trigger);
+}
+
+ProcessLoop::~ProcessLoop()
+{
+ _event_sources.remove_trigger(_wakeup_trigger);
+}
+
+int ProcessLoop::run()
+{
+ _thread = pthread_self();
+ _started = true;
+ for (;;) {
+ if (_event_sources.wait_events(_timers_queue.get_soonest_timeout())) {
+ _quitting = true;
+ break;
+ }
+ _timers_queue.timers_action();
+ process_events_queue();
+ if (_quitting) {
+ break;
+ }
+ }
+
+ return _exit_code;
+}
+
+void ProcessLoop::do_quit(int error_code)
+{
+ ASSERT(!_started || pthread_equal(pthread_self(), _thread));
+ if (_quitting) {
+ return;
+ }
+ _quitting = true;
+ _exit_code = error_code;
+}
+
+void ProcessLoop::quit(int error_code)
+{
+ AutoRef<QuitEvent> quit_event(new QuitEvent(error_code));
+ push_event(*quit_event);
+}
+
+void ProcessLoop::process_events_queue()
+{
+ ASSERT(!_started || pthread_equal(pthread_self(), _thread));
+ _events_queue.process_events();
+ if (!_events_queue.is_empty()) {
+ wakeup();
+ }
+}
+
+void ProcessLoop::wakeup()
+{
+ _wakeup_trigger.trigger();
+}
+
+void ProcessLoop::add_trigger(EventSources::Trigger& trigger)
+{
+ ASSERT(!_started || pthread_equal(pthread_self(), _thread));
+ _event_sources.add_trigger(trigger);
+}
+
+void ProcessLoop::remove_trigger(EventSources::Trigger& trigger)
+{
+ ASSERT(!_started || pthread_equal(pthread_self(), _thread));
+ _event_sources.remove_trigger(trigger);
+}
+
+void ProcessLoop::add_socket(EventSources::Socket& socket)
+{
+ ASSERT(!_started || pthread_equal(pthread_self(), _thread));
+ _event_sources.add_socket(socket);
+}
+
+void ProcessLoop::remove_socket(EventSources::Socket& socket)
+{
+ ASSERT(!_started || pthread_equal(pthread_self(), _thread));
+ _event_sources.remove_socket(socket);
+}
+
+void ProcessLoop::add_file(EventSources::File& file)
+{
+ ASSERT(!_started || pthread_equal(pthread_self(), _thread));
+ _event_sources.add_file(file);
+}
+
+void ProcessLoop::remove_file(EventSources::File& file)
+{
+ ASSERT(!_started || pthread_equal(pthread_self(), _thread));
+ _event_sources.remove_file(file);
+}
+
+void ProcessLoop::add_handle(EventSources::Handle& handle)
+{
+ ASSERT(!_started || pthread_equal(pthread_self(), _thread));
+ _event_sources.add_handle(handle);
+}
+
+void ProcessLoop::remove_handle(EventSources::Handle& handle)
+{
+ ASSERT(!_started || pthread_equal(pthread_self(), _thread));
+ _event_sources.remove_handle(handle);
+}
+
+void ProcessLoop::push_event(Event* event)
+{
+ int queue_size = _events_queue.push_event(event);
+ if (queue_size == 1) { // queue was empty before the push
+ wakeup();
+ }
+}
+
+void ProcessLoop::activate_interval_timer(Timer* timer, unsigned int millisec)
+{
+ _timers_queue.activate_interval_timer(timer, millisec);
+
+ if (_started && !pthread_equal(pthread_self(), _thread)) {
+ wakeup();
+ }
+}
+
+void ProcessLoop::deactivate_interval_timer(Timer* timer)
+{
+ _timers_queue.deactivate_interval_timer(timer);
+}
diff --git a/client/process_loop.h b/client/process_loop.h
new file mode 100644
index 00000000..0b052522
--- /dev/null
+++ b/client/process_loop.h
@@ -0,0 +1,233 @@
+/*
+ Copyright (C) 2009 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _H_PROCESS_LOOP
+#define _H_PROCESS_LOOP
+
+#include "common.h"
+
+#include <set>
+
+#include "event_sources.h"
+#include "threads.h"
+
+class AbstractProcessLoop {
+public:
+ virtual ~AbstractProcessLoop() {}
+ virtual int run() = 0;
+ virtual void do_quit(int error_code) = 0;
+ virtual void* get_owner() = 0;
+ virtual bool is_same_thread(pthread_t thread) = 0;
+};
+
+class EventBase {
+public:
+ EventBase() : _refs (1) {}
+
+ virtual void response(AbstractProcessLoop& events_loop) = 0;
+
+ EventBase* ref() { ++_refs; return this;}
+ void unref() {if (--_refs == 0) delete this;}
+
+protected:
+ virtual ~EventBase() {}
+
+private:
+ AtomicCount _refs;
+};
+
+class EventsQueue;
+
+class Event: public EventBase {
+#ifdef RED_DEBUG
+public:
+ Event() : _process_loop (NULL) {}
+
+private:
+ void set_process_loop(AbstractProcessLoop* process_loop) { _process_loop = process_loop;}
+
+protected:
+ AbstractProcessLoop* _process_loop;
+#endif
+
+private:
+ uint32_t _generation;
+
+ friend class EventsQueue;
+};
+
+class EventsQueue {
+public:
+ EventsQueue(AbstractProcessLoop& owner);
+ virtual ~EventsQueue();
+ /* return the size of the queue (post-push) */
+ int push_event(Event* event);
+ void process_events();
+ bool is_empty();
+
+private:
+ void clear_queue();
+
+private:
+ std::list<Event*> _events;
+ Mutex _events_lock;
+ uint32_t _events_gen;
+
+ AbstractProcessLoop& _owner;
+};
+
+class SyncEvent: public Event {
+public:
+ SyncEvent();
+
+ void wait();
+ bool success() { return !_err;}
+
+ virtual void do_response(AbstractProcessLoop& events_loop) {}
+
+protected:
+ virtual ~SyncEvent();
+
+private:
+ virtual void response(AbstractProcessLoop& events_loop);
+
+private:
+ Mutex _mutex;
+ Condition _condition;
+ bool _err;
+ bool _ready;
+};
+
+class TimersQueue;
+
+class Timer: public EventBase {
+public:
+ Timer();
+ bool is_armed() {return _is_armed;}
+
+protected:
+ virtual ~Timer();
+
+private:
+ void arm(uint32_t msec);
+ void disarm();
+ uint64_t get_expiration() const { return _expiration;}
+ void calc_next_expiration_time() { _expiration += _interval;}
+
+ static uint64_t get_now();
+
+private:
+ bool _is_armed;
+ uint32_t _interval;
+ uint64_t _expiration;
+
+ class Compare {
+ public:
+ bool operator () (const Timer* timer1, const Timer* timer2) const
+ {
+ if (timer1->get_expiration() < timer2->get_expiration()) {
+ return true;
+ } else if (timer1->get_expiration() > timer2->get_expiration()) {
+ return false;
+ } else { // elements must be unique (for insertion into set)
+ return timer1 < timer2;
+ }
+ }
+ };
+
+ friend class TimersQueue;
+};
+
+class TimersQueue {
+public:
+ TimersQueue(AbstractProcessLoop& owner);
+ virtual ~TimersQueue();
+
+ void activate_interval_timer(Timer* timer, unsigned int millisec);
+ void deactivate_interval_timer(Timer* timer);
+
+ int get_soonest_timeout();
+ void timers_action();
+
+private:
+ void clear_queue();
+
+private:
+ typedef std::set<Timer*, Timer::Compare> TimersSet;
+ TimersSet _armed_timers;
+ RecurciveMutex _timers_lock;
+ AbstractProcessLoop& _owner;
+};
+
+class ProcessLoop: public AbstractProcessLoop {
+public:
+ class QuitEvent;
+ ProcessLoop(void* owner);
+ virtual ~ProcessLoop();
+ int run();
+
+ void quit(int error_code);
+
+ /* Event sources to track. Note: the following methods are not thread safe, thus,
+ they mustn't be called from other thread than the process loop thread. */
+ void add_trigger(EventSources::Trigger& trigger);
+ void remove_trigger(EventSources::Trigger& trigger);
+ void add_socket(EventSources::Socket& socket);
+ void remove_socket(EventSources::Socket& socket);
+ void add_file(EventSources::File& file);
+ void remove_file(EventSources::File& file);
+ void add_handle(EventSources::Handle& handle);
+ void remove_handle(EventSources::Handle& handle);
+
+ /* events queue */
+ void push_event(Event* event);
+
+ void activate_interval_timer(Timer* timer, unsigned int millisec);
+ void deactivate_interval_timer(Timer* timer);
+
+ void process_events_queue();
+ void* get_owner() { return _owner;}
+
+ bool is_same_thread(pthread_t thread) { return _started && pthread_equal(_thread, thread);}
+
+protected:
+ class WakeupTrigger: public EventSources::Trigger {
+ public:
+ virtual void on_event() {}
+ };
+
+ void wakeup();
+ void do_quit(int error_code);
+
+ friend class QuitEvent; // allowing access to quit
+
+private:
+ EventSources _event_sources;
+ EventsQueue _events_queue;
+ TimersQueue _timers_queue;
+
+ WakeupTrigger _wakeup_trigger;
+
+ void* _owner;
+
+ bool _quitting;
+ int _exit_code;
+ bool _started;
+ pthread_t _thread;
+};
+
+#endif
diff --git a/client/red_client.cpp b/client/red_client.cpp
index 941321fb..2e4758cf 100644
--- a/client/red_client.cpp
+++ b/client/red_client.cpp
@@ -19,6 +19,7 @@
#include <math.h>
#include "red_client.h"
#include "application.h"
+#include "process_loop.h"
#include "utils.h"
#include "debug.h"
@@ -397,10 +398,12 @@ void RedClient::on_channel_disconnected(RedChannel& channel)
_notify_disconnect = false;
int connection_error = channel.get_connection_error();
if (connection_error == SPICEC_ERROR_CODE_SUCCESS) {
+ AutoRef<DisconnectedEvent> disconn_event(new DisconnectedEvent());
LOG_INFO("disconneted");
- push_event(new DisconnectedEvent());
+ push_event(*disconn_event);
} else {
- push_event(new CoonnectionError(connection_error));
+ AutoRef<ConnectionErrorEvent> error_event(new ConnectionErrorEvent(connection_error));
+ push_event(*error_event);
}
}
disconnect_channels();
diff --git a/client/red_client.h b/client/red_client.h
index d799e788..e22cefd9 100644
--- a/client/red_client.h
+++ b/client/red_client.h
@@ -29,9 +29,9 @@
#include "audio_channels.h"
#include "red.h"
#include "vd_agent.h"
+#include "process_loop.h"
class Application;
-class Event;
class MigChannel: public RedChannelBase {
public:
diff --git a/client/screen.cpp b/client/screen.cpp
index b33560ee..5d138a1c 100644
--- a/client/screen.cpp
+++ b/client/screen.cpp
@@ -30,9 +30,10 @@ class UpdateEvent: public Event {
public:
UpdateEvent(int screen) : _screen (screen) {}
- virtual void responce(Application& application)
+ virtual void response(AbstractProcessLoop& events_loop)
{
- RedScreen* screen = application.find_screen(_screen);
+ Application* app = static_cast<Application*>(events_loop.get_owner());
+ RedScreen* screen = app->find_screen(_screen);
if (screen) {
screen->update();
}
diff --git a/client/screen_layer.cpp b/client/screen_layer.cpp
index f521b465..9940ad86 100644
--- a/client/screen_layer.cpp
+++ b/client/screen_layer.cpp
@@ -24,18 +24,23 @@
class AttacheLayerEvent: public SyncEvent {
public:
- AttacheLayerEvent(ScreenLayer& layer, int screen_id) : _layer (layer), _screen_id (screen_id) {}
+ AttacheLayerEvent(ScreenLayer& layer, int screen_id)
+ : _layer (layer)
+ , _screen_id (screen_id)
+ {
+ }
- virtual void do_responce(Application& application);
+ virtual void do_response(AbstractProcessLoop& events_loop);
private:
ScreenLayer& _layer;
int _screen_id;
};
-void AttacheLayerEvent::do_responce(Application& application)
+void AttacheLayerEvent::do_response(AbstractProcessLoop& events_loop)
{
- AutoRef<RedScreen> screen(application.get_screen(_screen_id));
+ Application* app = (Application*)(events_loop.get_owner());
+ AutoRef<RedScreen> screen(app->get_screen(_screen_id));
(*screen)->attach_layer(_layer);
}
@@ -43,13 +48,13 @@ class DetacheLayerEvent: public SyncEvent {
public:
DetacheLayerEvent(ScreenLayer& _layer) : _layer (_layer) {}
- virtual void do_responce(Application& application);
+ virtual void do_response(AbstractProcessLoop& events_loop);
private:
ScreenLayer& _layer;
};
-void DetacheLayerEvent::do_responce(Application& application)
+void DetacheLayerEvent::do_response(AbstractProcessLoop& events_loop)
{
_layer.screen()->detach_layer(_layer);
}
diff --git a/client/tunnel_channel.cpp b/client/tunnel_channel.cpp
index 1d28ee48..5da18f56 100644
--- a/client/tunnel_channel.cpp
+++ b/client/tunnel_channel.cpp
@@ -256,18 +256,12 @@ TunnelChannel::TunnelChannel(RedClient& client, uint32_t id)
sizeof(RedTunnelSocketClosedAck));
handler->set_handler(RED_TUNNEL_SOCKET_DATA,
&TunnelChannel::handle_socket_data, sizeof(RedTunnelSocketData));
-#ifdef TUNNEL_CONFIG
- _config_listener = new TunnelConfigListenerIfc(*this);
-#endif
}
TunnelChannel::~TunnelChannel()
{
destroy_sockets();
OutSocketMessage::clear_free_messages();
-#ifdef TUNNEL_CONFIG
- delete _config_listener;
-#endif
}
void TunnelChannel::handle_init(RedPeer::InMessage* message)
@@ -587,10 +581,21 @@ void TunnelChannel::destroy_sockets()
}
}
+#ifdef TUNNEL_CONFIG
+void TunnelChannel::on_connect()
+{
+ _config_listener = new TunnelConfigListenerIfc(*this);
+
+}
+#endif
+
void TunnelChannel::on_disconnect()
{
destroy_sockets();
OutSocketMessage::clear_free_messages();
+#ifdef TUNNEL_CONFIG
+ delete _config_listener;
+#endif
}
#ifdef TUNNEL_CONFIG
@@ -646,23 +651,75 @@ ChannelFactory& TunnelChannel::Factory()
}
#ifdef TUNNEL_CONFIG
+class CreatePipeListenerEvent: public SyncEvent {
+public:
+ CreatePipeListenerEvent(NamedPipe::ListenerInterface& listener_ifc)
+ : _listener_ifc (listener_ifc)
+ {
+ }
+
+ virtual void do_response(AbstractProcessLoop& events_loop)
+ {
+ _listener_ref = NamedPipe::create(TUNNEL_CONFIG_PIPE_NAME, _listener_ifc);
+ }
+
+ NamedPipe::ListenerRef get_listener() { return _listener_ref;}
+private:
+ NamedPipe::ListenerInterface& _listener_ifc;
+ NamedPipe::ListenerRef _listener_ref;
+};
+
+class DestroyPipeListenerEvent: public SyncEvent {
+public:
+ DestroyPipeListenerEvent(NamedPipe::ListenerRef listener_ref)
+ : _listener_ref (listener_ref)
+ {
+ }
+
+ virtual void do_response(AbstractProcessLoop& events_loop)
+ {
+ NamedPipe::destroy(_listener_ref);
+ }
+
+private:
+ NamedPipe::ListenerRef _listener_ref;
+};
+
+class DestroyPipeConnectionEvent: public SyncEvent {
+public:
+ DestroyPipeConnectionEvent(NamedPipe::ConnectionRef ref) : _conn_ref(ref) {}
+ virtual void do_response(AbstractProcessLoop& events_loop)
+ {
+ NamedPipe::destroy_connection(_conn_ref);
+ }
+private:
+ NamedPipe::ConnectionRef _conn_ref;
+};
+
TunnelConfigListenerIfc::TunnelConfigListenerIfc(TunnelChannel& tunnel)
- : _tunnel(tunnel)
+ : _tunnel (tunnel)
{
- _listener_ref = NamedPipe::create(TUNNEL_CONFIG_PIPE_NAME, *this);
+ AutoRef<CreatePipeListenerEvent> event(new CreatePipeListenerEvent(*this));
+ _tunnel.get_client().push_event(*event);
+ (*event)->wait();
+ _listener_ref = (*event)->get_listener();
}
TunnelConfigListenerIfc::~TunnelConfigListenerIfc()
{
+ AutoRef<DestroyPipeListenerEvent> listen_event(new DestroyPipeListenerEvent(_listener_ref));
+ _tunnel.get_client().push_event(*listen_event);
+ (*listen_event)->wait();
for (std::list<TunnelConfigConnectionIfc*>::iterator it = _connections.begin();
it != _connections.end(); ++it) {
if ((*it)->get_ref() != NamedPipe::INVALID_CONNECTION) {
- NamedPipe::destroy_connection((*it)->get_ref());
+ AutoRef<DestroyPipeConnectionEvent> conn_event(new DestroyPipeConnectionEvent(
+ (*it)->get_ref()));
+ _tunnel.get_client().push_event(*conn_event);
+ (*conn_event)->wait();
}
delete (*it);
}
-
- NamedPipe::destroy(_listener_ref);
}
NamedPipe::ConnectionInterface& TunnelConfigListenerIfc::create()
@@ -684,11 +741,11 @@ void TunnelConfigListenerIfc::destroy_connection(TunnelConfigConnectionIfc* conn
TunnelConfigConnectionIfc::TunnelConfigConnectionIfc(TunnelChannel& tunnel,
TunnelConfigListenerIfc& listener)
- : _tunnel(tunnel)
- , _listener(listener)
- , _in_msg_len(0)
- , _out_msg("")
- , _out_msg_pos(0)
+ : _tunnel (tunnel)
+ , _listener (listener)
+ , _in_msg_len (0)
+ , _out_msg ("")
+ , _out_msg_pos (0)
{
}
diff --git a/client/tunnel_channel.h b/client/tunnel_channel.h
index 4fd3465c..b0f26977 100644
--- a/client/tunnel_channel.h
+++ b/client/tunnel_channel.h
@@ -61,6 +61,7 @@ protected:
class TunnelSocket;
virtual void on_disconnect();
+ virtual void on_connect();
private:
void handle_init(RedPeer::InMessage* message);
@@ -88,6 +89,7 @@ private:
uint32_t _service_group;
#ifdef TUNNEL_CONFIG
TunnelConfigListenerIfc* _config_listener;
+ friend class TunnelConfigListenerIfc;
#endif
};
diff --git a/client/windows/event_sources_p.cpp b/client/windows/event_sources_p.cpp
new file mode 100644
index 00000000..4a11b779
--- /dev/null
+++ b/client/windows/event_sources_p.cpp
@@ -0,0 +1,209 @@
+/*
+ Copyright (C) 2009 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "common.h"
+#include "event_sources.h"
+#include "debug.h"
+#include "utils.h"
+
+bool EventSources_p::process_system_events()
+{
+ MSG msg;
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+
+ if (msg.message == WM_QUIT) {
+ return true;
+ }
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ return false;
+}
+
+void EventSources_p::add_event(HANDLE event, EventSource* source)
+{
+ int size = _events.size();
+ _events.resize(size + 1);
+ _handles.resize(size + 1);
+ _events[size] = source;
+ _handles[size] = event;
+}
+
+void EventSources_p::remove_event(EventSource* source)
+{
+ int size = _events.size();
+ for (int i = 0; i < size; i++) {
+ if (_events[i] == source) {
+ for (i++; i < size; i++) {
+ _events[i - 1] = _events[i];
+ _handles[i - 1] = _handles[i];
+ }
+ _events.resize(size - 1);
+ _handles.resize(size - 1);
+ return;
+ }
+ }
+ THROW("event not found");
+}
+
+EventSources::EventSources()
+{
+}
+
+EventSources::~EventSources()
+{
+}
+
+bool EventSources::wait_events(int timeout_ms)
+{
+ if (_handles.empty()) {
+ if (WaitMessage()) {
+ return process_system_events();
+ } else {
+ THROW("wait failed %d", GetLastError());
+ }
+ }
+
+ DWORD wait_res = MsgWaitForMultipleObjectsEx(_handles.size(), &_handles[0], timeout_ms,
+ QS_ALLINPUT, 0);
+ if (wait_res == WAIT_TIMEOUT) {
+ return false;
+ }
+
+ if (wait_res == WAIT_FAILED) {
+ THROW("wait failed %d", GetLastError());
+ }
+
+ int event_index = wait_res - WAIT_OBJECT_0;
+ if (event_index == _handles.size()) {
+ return process_system_events();
+ } else if ((event_index >= 0) && (event_index < (int)_handles.size())) {
+ _events[event_index]->action();
+ return false;
+ } else {
+ THROW("invalid event id");
+ }
+}
+
+void EventSources::add_socket(Socket& socket)
+{
+ HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (!event) {
+ THROW("create event failed");
+ }
+ if (WSAEventSelect(socket.get_socket(), event,
+ FD_READ | FD_WRITE | FD_CLOSE) == SOCKET_ERROR) {
+ CloseHandle(event);
+ THROW("event select failed");
+ }
+ add_event(event, &socket);
+}
+
+void EventSources::remove_socket(Socket& socket)
+{
+ int size = _events.size();
+ for (int i = 0; i < size; i++) {
+ if (_events[i] == &socket) {
+ if (WSAEventSelect(socket.get_socket(), NULL, 0) == SOCKET_ERROR) {
+ THROW("event select failed");
+ }
+ u_long arg = 0;
+ if (ioctlsocket(socket.get_socket(), FIONBIO, &arg) == SOCKET_ERROR) {
+ THROW("set blocking mode failed");
+ }
+ CloseHandle(_handles[i]);
+ for (i++; i < size; i++) {
+ _events[i - 1] = _events[i];
+ _handles[i - 1] = _handles[i];
+ }
+ _events.resize(size - 1);
+ _handles.resize(size - 1);
+ return;
+ }
+ }
+ THROW("socket not found");
+}
+
+void EventSources::add_handle(Handle& handle)
+{
+ add_event(handle.get_handle(), &handle);
+}
+
+void EventSources::remove_handle(Handle& handle)
+{
+ remove_event(&handle);
+}
+
+Handle_p::Handle_p()
+{
+ if (!(_event = CreateEvent(NULL, FALSE, FALSE, NULL))) {
+ THROW("create event failed");
+ }
+}
+
+Handle_p::~Handle_p()
+{
+ CloseHandle(_event);
+}
+
+void EventSources::add_trigger(Trigger& trigger)
+{
+ add_event(trigger.get_handle(), &trigger);
+}
+
+void EventSources::remove_trigger(Trigger& trigger)
+{
+ remove_event(&trigger);
+}
+
+
+EventSources::Trigger::Trigger()
+{
+}
+
+EventSources::Trigger::~Trigger()
+{
+}
+
+
+void EventSources::Trigger::trigger()
+{
+ if (!SetEvent(_event)) {
+ THROW("set event failed");
+ }
+}
+
+void EventSources::Trigger::reset()
+{
+ if (!ResetEvent(_event)) {
+ THROW("set event failed");
+ }
+}
+
+void EventSources::Trigger::action()
+{
+ on_event();
+}
+
+void EventSources::add_file(File& file)
+{
+}
+
+void EventSources::remove_file(File& file)
+{
+}
+
diff --git a/client/windows/event_sources_p.h b/client/windows/event_sources_p.h
new file mode 100644
index 00000000..3477605e
--- /dev/null
+++ b/client/windows/event_sources_p.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2009 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _H_EVENT_SOURCES_P
+#define _H_EVENT_SOURCES_P
+
+#include "common.h"
+
+#include <vector>
+
+class EventSource;
+class Handle_p;
+
+class EventSources_p {
+protected:
+ /* return true if quit should be performed */
+ bool process_system_events();
+ void add_event(HANDLE event, EventSource* source);
+ void remove_event(EventSource* source);
+public:
+ std::vector<EventSource*> _events;
+ std::vector<HANDLE> _handles;
+};
+
+class Handle_p {
+public:
+ Handle_p();
+ virtual ~Handle_p();
+ HANDLE get_handle() { return _event;}
+protected:
+ HANDLE _event;
+};
+
+class Trigger_p: public Handle_p {
+};
+
+#endif
+
diff --git a/client/windows/events_loop_p.h b/client/windows/events_loop_p.h
index 8361398d..6bac7b94 100644
--- a/client/windows/events_loop_p.h
+++ b/client/windows/events_loop_p.h
@@ -22,15 +22,17 @@
#include <vector>
-class EventSource;
+class EventSourceOld;
class EventsLoop_p {
public:
- std::vector<EventSource*> _events;
+ class Trigger_p;
+public:
+ std::vector<EventSourceOld*> _events;
std::vector<HANDLE> _handles;
};
-class Trigger_p {
+class EventsLoop_p::Trigger_p {
public:
HANDLE get_handle() { return event;}
diff --git a/client/windows/named_pipe.cpp b/client/windows/named_pipe.cpp
index f33c476e..44459fab 100644
--- a/client/windows/named_pipe.cpp
+++ b/client/windows/named_pipe.cpp
@@ -20,23 +20,22 @@
#include "utils.h"
#include "debug.h"
-PipeBuffer::PipeBuffer(HANDLE pipe)
+PipeBuffer::PipeBuffer(HANDLE pipe, ProcessLoop& process_loop)
: _handler (NULL)
, _pipe (pipe)
, _start (0)
, _end (0)
, _pending (false)
+ , _process_loop(process_loop)
{
ZeroMemory(&_overlap, sizeof(_overlap));
- _overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- _event_handle = _overlap.hEvent;
- WinPlatform::add_event(*this);
+ _overlap.hEvent = this->get_handle();
+ _process_loop.add_handle(*this);
}
PipeBuffer::~PipeBuffer()
{
- WinPlatform::remove_event(*this);
- CloseHandle(_event_handle);
+ _process_loop.remove_handle(*this);
}
DWORD PipeBuffer::get_overlapped_bytes()
@@ -127,10 +126,10 @@ void PipeWriter::on_event()
}
}
-WinConnection::WinConnection(HANDLE pipe)
+WinConnection::WinConnection(HANDLE pipe, ProcessLoop& process_loop)
: _pipe (pipe)
- , _writer (pipe)
- , _reader (pipe)
+ , _writer (pipe, process_loop)
+ , _reader (pipe, process_loop)
{
}
@@ -158,24 +157,24 @@ void WinConnection::set_handler(NamedPipe::ConnectionInterface* handler)
_writer.set_handler(handler);
}
-WinListener::WinListener(const char *name, NamedPipe::ListenerInterface &listener_interface)
+WinListener::WinListener(const char *name, NamedPipe::ListenerInterface &listener_interface,
+ ProcessLoop& process_loop)
: _listener_interface (listener_interface)
, _pipe (0)
+ , _process_loop (process_loop)
{
_pipename = new TCHAR[PIPE_MAX_NAME_LEN];
swprintf_s(_pipename, PIPE_MAX_NAME_LEN, L"%s%S", PIPE_PREFIX, name);
ZeroMemory(&_overlap, sizeof(_overlap));
- _overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- _event_handle = _overlap.hEvent;
- WinPlatform::add_event(*this);
+ _overlap.hEvent = this->get_handle();
+ _process_loop.add_handle(*this);
create_pipe();
}
WinListener::~WinListener()
{
CancelIo(_pipe);
- WinPlatform::remove_event(*this);
- CloseHandle(_event_handle);
+ _process_loop.remove_handle(*this);
delete[] _pipename;
}
@@ -188,7 +187,7 @@ void WinListener::on_event()
return;
}
DBG(0, "Pipe connected 0x%p", _pipe);
- WinConnection *con = new WinConnection(_pipe);
+ WinConnection *con = new WinConnection(_pipe, _process_loop);
NamedPipe::ConnectionInterface &con_interface = _listener_interface.create();
con->set_handler(&con_interface);
con_interface.bind((NamedPipe::ConnectionRef)con);
@@ -213,7 +212,7 @@ void WinListener::create_pipe()
break;
case ERROR_PIPE_CONNECTED: {
DBG(0, "Pipe already connected");
- WinConnection *con = new WinConnection(_pipe);
+ WinConnection *con = new WinConnection(_pipe, _process_loop);
NamedPipe::ConnectionInterface &con_interface = _listener_interface.create();
con->set_handler(&con_interface);
con_interface.bind((NamedPipe::ConnectionRef)con);
diff --git a/client/windows/named_pipe.h b/client/windows/named_pipe.h
index 578c34d2..fcdc0dd7 100644
--- a/client/windows/named_pipe.h
+++ b/client/windows/named_pipe.h
@@ -19,8 +19,9 @@
#define _H_NAMED_PIPE
#include <windows.h>
+#include "process_loop.h"
+#include "event_sources.h"
#include "platform.h"
-#include "win_platform.h"
#define PIPE_TIMEOUT 5000
#define PIPE_BUF_SIZE 8192
@@ -29,9 +30,9 @@
class WinConnection;
-class PipeBuffer: public EventOwner {
+class PipeBuffer: public EventSources::Handle {
public:
- PipeBuffer(HANDLE pipe);
+ PipeBuffer(HANDLE pipe, ProcessLoop& process_loop);
~PipeBuffer();
void set_handler(NamedPipe::ConnectionInterface* handler) { _handler = handler;}
DWORD get_overlapped_bytes();
@@ -44,25 +45,26 @@ protected:
uint32_t _end;
uint8_t _data[PIPE_BUF_SIZE];
bool _pending;
+ ProcessLoop& _process_loop;
};
class PipeReader: public PipeBuffer {
public:
- PipeReader(HANDLE pipe) : PipeBuffer(pipe) {}
+ PipeReader(HANDLE pipe, ProcessLoop& process_loop) : PipeBuffer(pipe, process_loop) {}
int32_t read(uint8_t *buf, int32_t size);
void on_event();
};
class PipeWriter: public PipeBuffer {
public:
- PipeWriter(HANDLE pipe) : PipeBuffer(pipe) {}
+ PipeWriter(HANDLE pipe, ProcessLoop& process_loop) : PipeBuffer(pipe, process_loop) {}
int32_t write(const uint8_t *buf, int32_t size);
void on_event();
};
class WinConnection {
public:
- WinConnection(HANDLE pipe);
+ WinConnection(HANDLE pipe, ProcessLoop& process_loop);
~WinConnection();
int32_t read(uint8_t *buf, int32_t size);
int32_t write(const uint8_t *buf, int32_t size);
@@ -74,9 +76,10 @@ private:
PipeReader _reader;
};
-class WinListener: public EventOwner {
+class WinListener: public EventSources::Handle {
public:
- WinListener(const char *name, NamedPipe::ListenerInterface &listener_interface);
+ WinListener(const char *name, NamedPipe::ListenerInterface &listener_interface,
+ ProcessLoop& process_loop);
~WinListener();
void on_event();
@@ -88,6 +91,7 @@ private:
NamedPipe::ListenerInterface &_listener_interface;
OVERLAPPED _overlap;
HANDLE _pipe;
+ ProcessLoop& _process_loop;
};
#endif
diff --git a/client/windows/platform.cpp b/client/windows/platform.cpp
index 773fa614..b5faf758 100644
--- a/client/windows/platform.cpp
+++ b/client/windows/platform.cpp
@@ -28,9 +28,6 @@
#include "cursor.h"
#include "named_pipe.h"
-#define WM_USER_WAKEUP WM_USER
-#define NUM_TIMERS 100
-
int gdi_handlers = 0;
extern HINSTANCE instance;
@@ -44,61 +41,17 @@ public:
static DefaultEventListener default_event_listener;
static Platform::EventListener* event_listener = &default_event_listener;
static HWND paltform_win;
-static HANDLE main_tread;
-
-struct Timer {
- TimerID id;
- timer_proc_t proc;
- void* opaque;
- Timer *next;
-};
-
-Timer timers[NUM_TIMERS];
-Timer* free_timers = NULL;
-Mutex timers_lock;
-
-static void free_timer(Timer* timer)
-{
- Lock lock(timers_lock);
- timer->proc = NULL;
- timer->next = free_timers;
- free_timers = timer;
-}
+static ProcessLoop* main_loop = NULL;
-static void init_timers()
-{
- for (int i = 0; i < NUM_TIMERS; i++) {
- timers[i].id = i;
- free_timer(&timers[i]);
- }
-}
-
-static Timer* alloc_timer()
+void Platform::send_quit_request()
{
- Timer* timer;
-
- Lock lock(timers_lock);
- if (!(timer = free_timers)) {
- return NULL;
- }
-
- free_timers = free_timers->next;
- return timer;
+ ASSERT(main_loop);
+ main_loop->quit(0);
}
static LRESULT CALLBACK PlatformWinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
- case WM_TIMER: {
- TimerID id = wParam - 1;
- ASSERT(id < NUM_TIMERS);
- Timer* timer = &timers[id];
- timer->proc(timer->opaque, id);
- break;
- }
- case WM_USER_WAKEUP: {
- break;
- }
case WM_ACTIVATEAPP:
if (wParam) {
event_listener->on_app_activated();
@@ -147,80 +100,21 @@ static void create_message_wind()
paltform_win = window;
}
-void Platform::send_quit_request()
-{
- ASSERT(GetCurrentThread() == main_tread);
- PostQuitMessage(0);
-}
-
-static std::vector<HANDLE> events;
-static std::vector<EventOwner*> events_owners;
-
-void WinPlatform::add_event(EventOwner& event_owner)
-{
- ASSERT(main_tread == GetCurrentThread());
- int size = events.size();
- if (size == MAXIMUM_WAIT_OBJECTS - 1) {
- THROW("reached maximum allowed events to wait for");
- }
- events.resize(size + 1);
- events_owners.resize(size + 1);
- events[size] = event_owner.get_event_handle();
- events_owners[size] = &event_owner;
-}
-
-void WinPlatform::remove_event(EventOwner& event_owner)
-{
- ASSERT(main_tread == GetCurrentThread());
- int size = events.size();
- for (int i = 0; i < size; i++) {
- if (events_owners[i] == &event_owner) {
- for (i++; i < size; i++) {
- events[i - 1] = events[i];
- events_owners[i - 1] = events_owners[i];
- }
- events.resize(size - 1);
- events_owners.resize(size - 1);
- return;
- }
- }
- THROW("event owner not found");
-}
-
-void Platform::wait_events()
-{
- if (!events.size()) {
- if (!WaitMessage()) {
- THROW("wait failed %d", GetLastError());
- }
- return;
- }
-
- DWORD r = MsgWaitForMultipleObjectsEx(events.size(), &events[0], INFINITE, QS_ALLINPUT, 0);
- if (r == WAIT_OBJECT_0 + events.size()) {
- return;
- }
- if (r >= WAIT_OBJECT_0 && r <= WAIT_OBJECT_0 + events.size() - 1) {
- events_owners[r - WAIT_OBJECT_0]->on_event();
- } else if (r == WAIT_FAILED) {
- THROW("wait multiple failed %d", GetLastError());
- } else {
- THROW("unexpected wait return %u", r);
- }
-}
-
NamedPipe::ListenerRef NamedPipe::create(const char *name, ListenerInterface& listener_interface)
{
- return (ListenerRef)(new WinListener(name, listener_interface));
+ ASSERT(main_loop && main_loop->is_same_thread(pthread_self()));
+ return (ListenerRef)(new WinListener(name, listener_interface, *main_loop));
}
void NamedPipe::destroy(ListenerRef listener_ref)
{
+ ASSERT(main_loop && main_loop->is_same_thread(pthread_self()));
delete (WinListener *)listener_ref;
}
void NamedPipe::destroy_connection(ConnectionRef conn_ref)
{
+ ASSERT(main_loop && main_loop->is_same_thread(pthread_self()));
delete (WinConnection *)conn_ref;
}
@@ -234,26 +128,6 @@ int32_t NamedPipe::write(ConnectionRef conn_ref, const uint8_t *buf, int32_t siz
return ((WinConnection *)conn_ref)->write(buf, size);
}
-void Platform::wakeup()
-{
- if (!PostMessage(paltform_win, WM_USER_WAKEUP, 0, 0)) {
- THROW("post failed %d", GetLastError());
- }
-}
-
-bool Platform::process_events()
-{
- MSG msg;
- while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
- if (msg.message == WM_QUIT) {
- return true;
- }
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- return false;
-}
-
void Platform::msleep(unsigned int msec)
{
Sleep(msec);
@@ -302,48 +176,6 @@ void Platform::set_event_listener(EventListener* listener)
event_listener = listener ? listener : &default_event_listener;
}
-TimerID Platform::create_interval_timer(timer_proc_t proc, void* opaque)
-{
- Timer* timer = alloc_timer();
- if (!timer) {
- return INVALID_TIMER;
- }
- timer->proc = proc;
- timer->opaque = opaque;
- return timer->id;
-}
-
-bool Platform::activate_interval_timer(TimerID timer, unsigned int millisec)
-{
- if (timer >= NUM_TIMERS) {
- return false;
- }
-
- if (!SetTimer(paltform_win, timer + 1, millisec, NULL)) {
- return false;
- }
- return true;
-}
-
-bool Platform::deactivate_interval_timer(TimerID timer)
-{
- if (timer >= NUM_TIMERS) {
- return false;
- }
- KillTimer(paltform_win, timer + 1);
- return true;
-}
-
-void Platform::destroy_interval_timer(TimerID timer)
-{
- if (timer == INVALID_TIMER) {
- return;
- }
- ASSERT(timer < NUM_TIMERS);
- KillTimer(paltform_win, timer + 1);
- free_timer(&timers[timer]);
-}
-
uint64_t Platform::get_monolithic_time()
{
return uint64_t(GetTickCount()) * 1000 * 1000;
@@ -565,9 +397,12 @@ bool Platform::is_monitors_pos_valid()
void Platform::init()
{
- main_tread = GetCurrentThread();
create_message_wind();
- init_timers();
+}
+
+void Platform::set_process_loop(ProcessLoop& main_process_loop)
+{
+ main_loop = &main_process_loop;
}
WaveRecordAbstract* Platform::create_recorder(RecordClinet& client,
@@ -664,7 +499,7 @@ WinLocalCursor::WinLocalCursor(CursorData* cursor_data)
icon.yHotspot = header.hot_spot_y;
icon.hbmColor = icon.hbmMask = NULL;
HDC hdc = GetDC(NULL);
-
+
switch (header.type) {
case CURSOR_TYPE_ALPHA:
case CURSOR_TYPE_COLOR32:
@@ -784,3 +619,37 @@ Icon* Platform::load_icon(int id)
return new WinIcon(icon);
}
+class PlatformTimer: public Timer {
+public:
+ PlatformTimer(timer_proc_t proc, void* opaque) : _proc (proc), _opaque (opaque) {}
+ void response(AbstractProcessLoop& events_loop) {_proc(_opaque, (TimerID)this);}
+
+private:
+ timer_proc_t _proc;
+ void* _opaque;
+};
+
+TimerID Platform::create_interval_timer(timer_proc_t proc, void* opaque)
+{
+ return (TimerID)(new PlatformTimer(proc, opaque));
+}
+
+bool Platform::activate_interval_timer(TimerID timer, unsigned int millisec)
+{
+ ASSERT(main_loop);
+ main_loop->activate_interval_timer((PlatformTimer*)timer, millisec);
+ return true;
+}
+
+bool Platform::deactivate_interval_timer(TimerID timer)
+{
+ ASSERT(main_loop);
+ main_loop->deactivate_interval_timer((PlatformTimer*)timer);
+ return true;
+}
+
+void Platform::destroy_interval_timer(TimerID timer)
+{
+ deactivate_interval_timer(timer);
+ ((PlatformTimer*)timer)->unref();
+}
diff --git a/client/windows/redc.vcproj b/client/windows/redc.vcproj
index f65e3a2f..c63e1f1c 100644
--- a/client/windows/redc.vcproj
+++ b/client/windows/redc.vcproj
@@ -225,6 +225,10 @@
>
</File>
<File
+ RelativePath=".\event_sources_p.cpp"
+ >
+ </File>
+ <File
RelativePath=".\events_loop_p.cpp"
>
</File>
@@ -311,6 +315,10 @@
>
</File>
<File
+ RelativePath="..\process_loop.cpp"
+ >
+ </File>
+ <File
RelativePath="..\quic.cpp"
>
</File>
@@ -437,6 +445,14 @@
>
</File>
<File
+ RelativePath="..\event_sources.h"
+ >
+ </File>
+ <File
+ RelativePath=".\event_sources_p.h"
+ >
+ </File>
+ <File
RelativePath="..\events_loop.h"
>
</File>
@@ -513,6 +529,10 @@
>
</File>
<File
+ RelativePath="..\process_loop.h"
+ >
+ </File>
+ <File
RelativePath=".\record.h"
>
</File>
diff --git a/client/windows/win_platform.h b/client/windows/win_platform.h
index ddd0cd59..a821f63d 100644
--- a/client/windows/win_platform.h
+++ b/client/windows/win_platform.h
@@ -20,22 +20,6 @@
#include "icon.h"
-class EventOwner {
-public:
- EventOwner() : _event_handle (0) {}
- HANDLE const get_event_handle() { return _event_handle;}
- virtual void on_event() = 0;
-
-protected:
- HANDLE _event_handle;
-};
-
-class WinPlatform {
-public:
- static void add_event(EventOwner& event_owner);
- static void remove_event(EventOwner& event_owner);
-};
-
class WinIcon: public Icon {
public:
WinIcon(HICON icon) : _icon (icon) {}
diff --git a/client/x11/Makefile.am b/client/x11/Makefile.am
index 06909a81..fffd36c8 100644
--- a/client/x11/Makefile.am
+++ b/client/x11/Makefile.am
@@ -72,6 +72,7 @@ RED_COMMON_SRCS = \
$(top_srcdir)/client/pixels_source.h \
$(top_srcdir)/client/platform.h \
$(top_srcdir)/client/playback_channel.cpp \
+ $(top_srcdir)/client/process_loop.cpp \
$(top_srcdir)/client/quic.cpp \
$(top_srcdir)/client/record_channel.cpp \
$(top_srcdir)/client/red_channel.cpp \
@@ -110,6 +111,7 @@ spicec_SOURCES = \
atomic_count.h \
events_loop_p.cpp \
events_loop_p.h \
+ event_sources_p.cpp \
main.cpp \
named_pipe.h \
named_pipe.cpp \
diff --git a/client/x11/event_sources_p.cpp b/client/x11/event_sources_p.cpp
new file mode 100644
index 00000000..2e6af138
--- /dev/null
+++ b/client/x11/event_sources_p.cpp
@@ -0,0 +1,339 @@
+/*
+ Copyright (C) 2009 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <sys/epoll.h>
+#include <sys/fcntl.h>
+
+#include "event_sources.h"
+#include "debug.h"
+#include "utils.h"
+
+#ifdef USING_EVENT_FD
+#include <sys/eventfd.h>
+#endif
+
+#define NUM_EPOLL_EVENTS 10
+
+#ifdef USING_EVENT_FD
+#define WRITE_FD _event_fd
+#define EVENT_DATA_TYPE eventfd_t
+#else
+#define WRITE_FD _event_write_fd
+#define EVENT_DATA_TYPE uint8_t
+#endif
+
+class EventWrapper {
+public:
+ EventWrapper(EventSources& owner, EventSource& event)
+ : _owner (owner)
+ , _event (&event)
+ , _refs (1)
+ {
+ }
+
+ EventWrapper* ref()
+ {
+ _refs++;
+ return this;
+ }
+
+ void unref()
+ {
+ if (!--_refs) {
+ _owner.remove_wrapper(this);
+ delete this;
+ }
+ }
+
+ EventSource* get_event()
+ {
+ return _event;
+ }
+
+ void invalidate()
+ {
+ _event = NULL;
+ }
+
+private:
+ EventSources& _owner;
+ EventSource* _event;
+ int _refs;
+};
+
+EventSources::EventSources()
+{
+ _epoll = epoll_create(NUM_EPOLL_EVENTS);
+ if (_epoll == -1) {
+ THROW("create epool failed");
+ }
+}
+
+EventSources::~EventSources()
+{
+ Events::iterator iter = _events.begin();
+ for (; iter != _events.end(); iter++) {
+ delete *iter;
+ }
+ close(_epoll);
+}
+
+bool EventSources::wait_events(int timeout_ms)
+{
+ struct epoll_event events[NUM_EPOLL_EVENTS];
+ int num_events = epoll_wait(_epoll, events, NUM_EPOLL_EVENTS, timeout_ms);
+
+ if (num_events == -1) {
+ if (errno == EINTR) {
+ return false;
+ }
+ THROW("wait error eventfd failed");
+ }
+
+ for (int i = 0; i < num_events; i++) {
+ ((EventWrapper*)events[i].data.ptr)->ref();
+ }
+
+ for (int i = 0; i < num_events; i++) {
+ EventWrapper* wrapper;
+ EventSource* event;
+
+ wrapper = (EventWrapper *)events[i].data.ptr;
+ if ((event = wrapper->get_event())) {
+ event->action();
+ }
+ wrapper->unref();
+ }
+ return false;
+}
+
+void EventSources::add_trigger(Trigger& trigger)
+{
+ int fd = trigger.get_fd();
+ EventWrapper* wrapper = new EventWrapper(*this, trigger);
+ struct epoll_event event;
+ event.data.ptr = wrapper;
+ event.events = EPOLLIN;
+ if (epoll_ctl(_epoll, EPOLL_CTL_ADD, fd, &event) == -1) {
+ THROW("epoll add failed");
+ }
+ _events.push_back(wrapper);
+}
+
+void EventSources_p::remove_wrapper(EventWrapper* wrapper)
+{
+ Events::iterator iter = _events.begin();
+ for (;; iter++) {
+ if (iter == _events.end()) {
+ THROW("wrapper not found");
+ }
+ if ((*iter) == wrapper) {
+ _events.erase(iter);
+ return;
+ }
+ }
+}
+
+void EventSources::remove_trigger(Trigger& trigger)
+{
+ Events::iterator iter = _events.begin();
+ for (;; iter++) {
+ if (iter == _events.end()) {
+ THROW("trigger not found");
+ }
+ if ((*iter)->get_event() == &trigger) {
+ (*iter)->invalidate();
+ (*iter)->unref();
+ break;
+ }
+ }
+ int fd = trigger.get_fd();
+ if (epoll_ctl(_epoll, EPOLL_CTL_DEL, fd, NULL) == -1) {
+ THROW("epoll remove failed");
+ }
+}
+
+EventSources::Trigger::Trigger()
+{
+#ifdef USING_EVENT_FD
+ _event_fd = eventfd(0, 0);
+ if (_event_fd == -1) {
+ THROW("create eventfd failed");
+ }
+#else
+ int fd[2];
+ if (pipe(fd) == -1) {
+ THROW("create pipe failed");
+ }
+ _event_fd = fd[0];
+ _event_write_fd = fd[1];
+#endif
+ int flags;
+ if ((flags = fcntl(_event_fd, F_GETFL)) == -1) {
+ THROW("failed to set eventfd non block: %s", strerror(errno));
+ }
+
+ if (fcntl(_event_fd, F_SETFL, flags | O_NONBLOCK) == -1) {
+ THROW("failed to set eventfd non block: %s", strerror(errno));
+ }
+}
+
+EventSources::Trigger::~Trigger()
+{
+ close(_event_fd);
+#ifndef USING_EVENT_FD
+ close(_event_write_fd);
+#endif
+}
+
+void EventSources::Trigger::trigger()
+{
+ Lock lock(_lock);
+ if (_pending_int) {
+ return;
+ }
+ _pending_int = true;
+ static const EVENT_DATA_TYPE val = 1;
+ if (::write(WRITE_FD, &val, sizeof(val)) != sizeof(val)) {
+ THROW("write event failed");
+ }
+}
+
+bool Trigger_p::reset_event()
+{
+ Lock lock(_lock);
+ if (!_pending_int) {
+ return false;
+ }
+ EVENT_DATA_TYPE val;
+ if (read(_event_fd, &val, sizeof(val)) != sizeof(val)) {
+ THROW("event read error");
+ }
+ _pending_int = false;
+ return true;
+}
+
+void EventSources::Trigger::reset()
+{
+ reset_event();
+}
+
+void EventSources::Trigger::action()
+{
+ if (reset_event()) {
+ on_event();
+ }
+}
+
+static void set_non_blocking(int fd)
+{
+ int flags;
+ if ((flags = fcntl(fd, F_GETFL)) == -1) {
+ THROW("failed to set socket non block: %s", strerror(errno));
+ }
+
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
+ THROW("failed to set socket non block: %s", strerror(errno));
+ }
+}
+
+static void set_blocking(int fd)
+{
+ int flags;
+ if ((flags = fcntl(fd, F_GETFL)) == -1) {
+ THROW("failed to clear socket non block: %s", strerror(errno));
+ }
+
+ if (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) == -1) {
+ THROW("failed to clear socket non block: %s", strerror(errno));
+ }
+}
+
+static void add_to_poll(int fd, int epoll, EventWrapper* wrapper)
+{
+ struct epoll_event event;
+ event.data.ptr = wrapper;
+ event.events = EPOLLIN | EPOLLOUT | EPOLLET;
+ if (epoll_ctl(epoll, EPOLL_CTL_ADD, fd, &event) == -1) {
+ THROW("epoll add failed");
+ }
+}
+
+void EventSources::add_socket(Socket& socket)
+{
+ int fd = socket.get_socket();
+ set_non_blocking(fd);
+ EventWrapper* wrapper = new EventWrapper(*this, socket);
+ add_to_poll(fd, _epoll, wrapper);
+ _events.push_back(wrapper);
+}
+
+static bool remove_event(EventSources_p::Events& events, EventSource& event)
+{
+ EventSources_p::Events::iterator iter = events.begin();
+ for (;; iter++) {
+ if (iter == events.end()) {
+ return false;
+ }
+ if ((*iter)->get_event() == &event) {
+ (*iter)->invalidate();
+ (*iter)->unref();
+ return true;
+ }
+ }
+}
+
+void EventSources::remove_socket(Socket& socket)
+{
+ if (!remove_event(_events, socket)) {
+ THROW("socket not found");
+ }
+ int fd = socket.get_socket();
+ if (epoll_ctl(_epoll, EPOLL_CTL_DEL, fd, NULL) == -1) {
+ THROW("epoll remove failed");
+ }
+ set_blocking(fd);
+}
+
+void EventSources::add_file(File& file)
+{
+ int fd = file.get_fd();
+ set_non_blocking(fd);
+ EventWrapper* wrapper = new EventWrapper(*this, file);
+ add_to_poll(fd, _epoll, wrapper);
+ _events.push_back(wrapper);
+}
+
+void EventSources::remove_file(File& file)
+{
+ if (!remove_event(_events, file)) {
+ THROW("file not found");
+ }
+ int fd = file.get_fd();
+ if (epoll_ctl(_epoll, EPOLL_CTL_DEL, fd, NULL) == -1) {
+ THROW("epoll remove failed");
+ }
+ set_blocking(fd);
+}
+
+void EventSources::add_handle(Handle& file)
+{
+}
+
+void EventSources::remove_handle(Handle& file)
+{
+}
diff --git a/client/x11/event_sources_p.h b/client/x11/event_sources_p.h
new file mode 100644
index 00000000..591a781f
--- /dev/null
+++ b/client/x11/event_sources_p.h
@@ -0,0 +1,63 @@
+/*
+ Copyright (C) 2009 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _H_EVENT_SOURCES_P
+#define _H_EVENT_SOURCES_P
+
+#include "common.h"
+#include "threads.h"
+
+#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)
+#define USING_EVENT_FD
+#endif
+
+#define INFINITE -1
+
+class EventWrapper;
+
+class EventSources_p {
+public:
+ void remove_wrapper(EventWrapper*);
+
+public:
+ int _epoll;
+ typedef std::list<EventWrapper*> Events;
+ Events _events;
+
+ friend class EventWrapper;
+};
+
+class Trigger_p {
+public:
+ Trigger_p() : _pending_int (false) {}
+ int get_fd() { return _event_fd;}
+ bool reset_event();
+
+public:
+ int _event_fd;
+#ifndef USING_EVENT_FD
+ int _event_write_fd;
+#endif
+ bool _pending_int;
+ Mutex _lock;
+};
+
+class Handle_p {
+};
+
+#endif
+
diff --git a/client/x11/events_loop_p.cpp b/client/x11/events_loop_p.cpp
index 4db1469c..a1c450b5 100644
--- a/client/x11/events_loop_p.cpp
+++ b/client/x11/events_loop_p.cpp
@@ -38,7 +38,7 @@
class EventWrapper {
public:
- EventWrapper(EventsLoop& owner, EventSource& event)
+ EventWrapper(EventsLoop& owner, EventSourceOld& event)
: _owner (owner)
, _event (&event)
, _refs (1)
@@ -59,7 +59,7 @@ public:
}
}
- EventSource* get_event()
+ EventSourceOld* get_event()
{
return _event;
}
@@ -71,7 +71,7 @@ public:
private:
EventsLoop& _owner;
- EventSource* _event;
+ EventSourceOld* _event;
int _refs;
};
@@ -116,7 +116,7 @@ void EventsLoop::run_once(int timeout_milli)
}
for (int i = 0; i < num_events; i++) {
EventWrapper* wrapper;
- EventSource* event;
+ EventSourceOld* event;
wrapper = (EventWrapper *)events[i].data.ptr;
if ((event = wrapper->get_event())) {
@@ -218,7 +218,7 @@ void EventsLoop::Trigger::trigger()
}
}
-bool Trigger_p::reset_event()
+bool EventsLoop_p::Trigger_p::reset_event()
{
Lock lock(_lock);
if (!_pending_int) {
@@ -287,7 +287,7 @@ void EventsLoop::add_socket(Socket& socket)
_events.push_back(wrapper);
}
-static bool remove_event(EventsLoop_p::Events& events, EventSource& event)
+static bool remove_event(EventsLoop_p::Events& events, EventSourceOld& event)
{
EventsLoop_p::Events::iterator iter = events.begin();
for (;; iter++) {
diff --git a/client/x11/events_loop_p.h b/client/x11/events_loop_p.h
index 0a70d3ed..d339ca4b 100644
--- a/client/x11/events_loop_p.h
+++ b/client/x11/events_loop_p.h
@@ -31,6 +31,7 @@ class EventWrapper;
class EventsLoop_p {
public:
+ class Trigger_p;
void remove_wrapper(EventWrapper*);
public:
@@ -41,7 +42,7 @@ public:
friend class EventWrapper;
};
-class Trigger_p {
+class EventsLoop_p::Trigger_p {
public:
Trigger_p() : _pending_int (false) {}
int get_fd() { return _event_fd;}
diff --git a/client/x11/named_pipe.cpp b/client/x11/named_pipe.cpp
index 73d103c0..18c390e3 100644
--- a/client/x11/named_pipe.cpp
+++ b/client/x11/named_pipe.cpp
@@ -23,7 +23,7 @@
#include "utils.h"
#include "debug.h"
-Session::Session(int fd, EventsLoop& events_loop)
+Session::Session(int fd, ProcessLoop& events_loop)
: _fd_client(fd)
, _events_loop(events_loop)
{
@@ -121,7 +121,7 @@ int LinuxListener::create_socket(const char *socket_name)
}
LinuxListener::LinuxListener(const char *name, NamedPipe::ListenerInterface &listener_interface,
- EventsLoop &events_loop)
+ ProcessLoop& events_loop)
: _listener_interface (listener_interface)
, _events_loop (events_loop)
{
diff --git a/client/x11/named_pipe.h b/client/x11/named_pipe.h
index ab41f7f3..b32ede88 100644
--- a/client/x11/named_pipe.h
+++ b/client/x11/named_pipe.h
@@ -20,11 +20,11 @@
#include "platform.h"
#include "x_platform.h"
-#include "events_loop.h"
+#include "process_loop.h"
-class Session: public EventsLoop::Socket {
+class Session: public EventSources::Socket {
public:
- Session(int fd, EventsLoop& events_loop);
+ Session(int fd, ProcessLoop& events_loop);
virtual ~Session();
void bind(NamedPipe::ConnectionInterface* conn_interface);
@@ -37,13 +37,13 @@ public:
private:
NamedPipe::ConnectionInterface *_conn_interface;
int _fd_client;
- EventsLoop &_events_loop;
+ ProcessLoop &_events_loop;
};
-class LinuxListener: public EventsLoop::Socket {
+class LinuxListener: public EventSources::Socket {
public:
LinuxListener(const char *name, NamedPipe::ListenerInterface &listener_interface,
- EventsLoop &events_loop);
+ ProcessLoop& events_loop);
virtual ~LinuxListener();
void on_event();
virtual int get_socket() {return _listen_socket;}
@@ -55,7 +55,7 @@ private:
NamedPipe::ListenerInterface &_listener_interface;
int _listen_socket;
std::string _name;
- EventsLoop &_events_loop;
+ ProcessLoop &_events_loop;
};
#endif
diff --git a/client/x11/platform.cpp b/client/x11/platform.cpp
index f0c68235..8f318f2d 100644
--- a/client/x11/platform.cpp
+++ b/client/x11/platform.cpp
@@ -50,7 +50,7 @@
#include "resource.h"
#include "res.h"
#include "cursor.h"
-#include "events_loop.h"
+#include "process_loop.h"
#define DWORD uint32_t
#define BOOL bool
@@ -66,10 +66,8 @@ static Display* x_display = NULL;
static XVisualInfo **vinfo = NULL;
static GLXFBConfig **fb_config;
-static EventsLoop events_loop;
static XContext win_proc_context;
-static bool quit_request = false;
-static pthread_t main_thread;
+static ProcessLoop* main_loop = NULL;
static int focus_count = 0;
static bool using_xrandr_1_0 = false;
@@ -108,16 +106,19 @@ static Platform::DisplayModeListner* display_mode_listener = &default_display_mo
NamedPipe::ListenerRef NamedPipe::create(const char *name, ListenerInterface& listener_interface)
{
- return (ListenerRef)(new LinuxListener(name, listener_interface, events_loop));
+ ASSERT(main_loop && main_loop->is_same_thread(pthread_self()));
+ return (ListenerRef)(new LinuxListener(name, listener_interface, *main_loop));
}
void NamedPipe::destroy(ListenerRef listener_ref)
{
+ ASSERT(main_loop && main_loop->is_same_thread(pthread_self()));
delete (LinuxListener *)listener_ref;
}
void NamedPipe::destroy_connection(ConnectionRef conn_ref)
{
+ ASSERT(main_loop && main_loop->is_same_thread(pthread_self()));
delete (Session *)conn_ref;
}
@@ -137,81 +138,45 @@ int32_t NamedPipe::write(ConnectionRef conn_ref, const uint8_t* buf, int32_t siz
return -1;
}
-class XEventHandler: public EventsLoop::File {
+class XEventHandler: public EventSources::File {
public:
- XEventHandler(Display& x_display);
- virtual void on_event() {}
+ XEventHandler(Display& x_display, XContext& win_proc_context);
+ virtual void on_event();
virtual int get_fd() {return _x_fd;}
private:
+ Display& _x_display;
+ XContext& _win_proc_context;
int _x_fd;
};
-XEventHandler::XEventHandler(Display& x_display)
+XEventHandler::XEventHandler(Display& x_display, XContext& win_proc_context)
+ : _x_display (x_display)
+ , _win_proc_context (win_proc_context)
{
if ((_x_fd = ConnectionNumber(&x_display)) == -1) {
THROW("get x fd failed");
}
}
-class WakeupEventHandler: public EventsLoop::Trigger {
-public:
- virtual void on_event() {}
-};
-
-static WakeupEventHandler wakeup_handler;
-
-#define NSEC_PER_SEC (1000 * 1000 * 1000)
-
-class Timer {
-public:
- Timer(timer_proc_t proc, void* opaque);
- ~Timer();
-
- void arm(uint32_t msec);
- void disarm();
- bool action(const timespec& now);
-
- const timespec& get_experatoin() const { return _experatoin;}
-
- static int get_timout();
- static void timers_action();
-
-private:
- void calc_next_experatoin_time();
-
- static bool timespec_less(const timespec& time, const timespec& from);
- static bool timespec_equal(const timespec& time, const timespec& from);
- static bool timespec_less_or_equal(const timespec& time, const timespec& from);
-
-public:
- static RecurciveMutex timers_lock;
+void XEventHandler::on_event()
+{
+ while (XPending(&_x_display)) {
+ XPointer proc_pointer;
+ XEvent event;
-private:
- timer_proc_t _proc;
- void* _opaque;
- bool _armed;
- timespec _interval;
- timespec _experatoin;
-
- class Compare {
- public:
- bool operator () (const Timer* timer1, const Timer* timer2) const
- {
- if (!Timer::timespec_less(timer1->get_experatoin(), timer2->get_experatoin())) {
- return Timer::timespec_equal(timer1->get_experatoin(), timer2->get_experatoin()) ?
- timer1 < timer2 : false;
- }
- return true;
+ XNextEvent(&_x_display, &event);
+ if (event.xany.window == None) {
+ LOG_WARN("invalid window");
+ continue;
}
- };
- typedef std::set<Timer*, Compare> TimersSet;
- static TimersSet armed_timers;
-};
-
-Timer::TimersSet Timer::armed_timers;
-RecurciveMutex Timer::timers_lock;
+ if (XFindContext(&_x_display, event.xany.window, _win_proc_context, &proc_pointer)) {
+ THROW("no window proc");
+ }
+ ((XPlatform::win_proc_t)proc_pointer)(event);
+ }
+}
Display* XPlatform::get_display()
{
@@ -242,44 +207,8 @@ void XPlatform::cleare_win_proc(Window win)
void Platform::send_quit_request()
{
- quit_request = true;
- wakeup();
-}
-
-void Platform::wait_events()
-{
- ASSERT(pthread_self() == main_thread);
- XFlush(x_display);
- if (!XPending(x_display)) {
- events_loop.run_once(Timer::get_timout());
- Timer::timers_action();
- }
-}
-
-void Platform::wakeup()
-{
- wakeup_handler.trigger();
-}
-
-bool Platform::process_events()
-{
- ASSERT(pthread_self() == main_thread);
- while (XPending(x_display)) {
- XPointer proc_pointer;
- XEvent event;
-
- XNextEvent(x_display, &event);
- if (event.xany.window == None) {
- LOG_WARN("invalid window");
- continue;
- }
-
- if (XFindContext(x_display, event.xany.window, win_proc_context, &proc_pointer)) {
- THROW("no window proc");
- }
- ((XPlatform::win_proc_t)proc_pointer)(event);
- }
- return quit_request;
+ ASSERT(main_loop);
+ main_loop->quit(0);
}
uint64_t Platform::get_monolithic_time()
@@ -341,155 +270,6 @@ void Platform::set_thread_priority(void* thread, Platform::ThreadPriority in_pri
}
}
-Timer::Timer(timer_proc_t proc, void* opaque)
- : _proc (proc)
- , _opaque (opaque)
- , _armed (false)
-{
-}
-
-Timer::~Timer()
-{
- disarm();
-}
-
-void Timer::arm(uint32_t msec)
-{
- disarm();
- _interval.tv_sec = msec / 1000;
- _interval.tv_nsec = (msec % 1000) * 1000 * 1000;
- if (clock_gettime(CLOCK_MONOTONIC, &_experatoin)) {
- THROW("gettime failed %s", strerror(errno));
- }
- calc_next_experatoin_time();
- _armed = true;
- armed_timers.insert(this);
-}
-
-void Timer::disarm()
-{
- if (!_armed) {
- return;
- }
- armed_timers.erase(this);
- _armed = false;
-}
-
-#define TINER_COMPENSATION
-
-bool Timer::action(const timespec& now)
-{
- ASSERT(_armed);
- ASSERT(now.tv_nsec < NSEC_PER_SEC);
-
- if (timespec_less(now, _experatoin)) {
- return false;
- }
- armed_timers.erase(this);
-#ifndef TINER_COMPENSATION
- _experatoin = now;
-#endif
- calc_next_experatoin_time();
-#ifdef TINER_COMPENSATION
- if (timespec_less_or_equal(_experatoin, now)) {
- _experatoin = now;
- calc_next_experatoin_time();
- }
-#endif
- armed_timers.insert(this);
- _proc(_opaque, (TimerID)this);
- return true;
-}
-
-int Timer::get_timout()
-{
- RecurciveLock lock(Timer::timers_lock);
- TimersSet::iterator iter;
- iter = armed_timers.begin();
- if (iter == armed_timers.end()) {
- return -1;
- }
-
- timespec now;
- if (clock_gettime(CLOCK_MONOTONIC, &now)) {
- THROW("gettime failed %s", strerror(errno));
- }
-
- const timespec& next_time = (*iter)->get_experatoin();
-
- if (!timespec_less(now, next_time)) {
- return 0;
- }
- return ((next_time.tv_nsec - now.tv_nsec) / 1000 / 1000) +
- (next_time.tv_sec - now.tv_sec) * 1000;
-}
-
-void Timer::timers_action()
-{
- RecurciveLock lock(timers_lock);
- timespec now;
- if (clock_gettime(CLOCK_MONOTONIC, &now)) {
- THROW("gettime failed %s", strerror(errno));
- }
-
- TimersSet::iterator iter;
- while ((iter = armed_timers.begin()) != armed_timers.end() && (*iter)->action(now));
-}
-
-void Timer::calc_next_experatoin_time()
-{
- _experatoin.tv_nsec += _interval.tv_nsec;
- _experatoin.tv_sec += (_experatoin.tv_nsec / NSEC_PER_SEC) + _interval.tv_sec;
- _experatoin.tv_nsec %= NSEC_PER_SEC;
-}
-
-bool Timer::timespec_less(const timespec& time, const timespec& from)
-{
- return time.tv_sec < from.tv_sec || (time.tv_sec == from.tv_sec && time.tv_nsec < from.tv_nsec);
-}
-
-bool Timer::timespec_equal(const timespec& time, const timespec& from)
-{
- return time.tv_sec == from.tv_sec && time.tv_nsec <= from.tv_nsec;
-}
-
-bool Timer::timespec_less_or_equal(const timespec& time, const timespec& from)
-{
- return time.tv_sec < from.tv_sec ||
- (time.tv_sec == from.tv_sec && time.tv_nsec <= from.tv_nsec);
-}
-
-TimerID Platform::create_interval_timer(timer_proc_t proc, void* opaque)
-{
- return (TimerID) new Timer(proc, opaque);
-}
-
-bool Platform::activate_interval_timer(TimerID timer, unsigned int millisec)
-{
- RecurciveLock lock(Timer::timers_lock);
- ((Timer*)timer)->arm(millisec);
- if (pthread_self() != main_thread) {
- wakeup();
- }
- return true;
-}
-
-bool Platform::deactivate_interval_timer(TimerID timer)
-{
- RecurciveLock lock(Timer::timers_lock);
- ((Timer*)timer)->disarm();
- return true;
-}
-
-void Platform::destroy_interval_timer(TimerID timer)
-{
- if (timer == INVALID_TIMER) {
- return;
- }
- RecurciveLock lock(Timer::timers_lock);
- delete (Timer*)timer;
-}
-
void Platform::set_event_listener(EventListener* listener)
{
event_listener = listener ? listener : &default_event_listener;
@@ -2278,13 +2058,11 @@ void Platform::init()
{
int err, ev;
int threads_enable;
- XEventHandler *x_event_handler;
DBG(0, "");
threads_enable = XInitThreads();
- main_thread = pthread_self();
if (!(x_display = XOpenDisplay(NULL))) {
THROW("open X display failed");
@@ -2341,10 +2119,6 @@ void Platform::init()
init_xrandr();
init_xrender();
- x_event_handler = new XEventHandler(*x_display);
- events_loop.add_file(*x_event_handler);
- events_loop.add_trigger(wakeup_handler);
-
struct sigaction act;
memset(&act, 0, sizeof(act));
sigfillset(&act.sa_mask);
@@ -2368,6 +2142,14 @@ void Platform::init()
atexit(cleanup);
}
+void Platform::set_process_loop(ProcessLoop& main_process_loop)
+{
+ main_loop = &main_process_loop;
+ XEventHandler *x_event_handler;
+ x_event_handler = new XEventHandler(*x_display, win_proc_context);
+ main_loop->add_file(*x_event_handler);
+}
+
uint32_t Platform::get_keyboard_modifiers()
{
XKeyboardState keyboard_state;
@@ -2641,3 +2423,37 @@ LocalCursor* Platform::create_default_cursor()
return new XDefaultCursor();
}
+class PlatformTimer: public Timer {
+public:
+ PlatformTimer(timer_proc_t proc, void* opaque) : _proc(proc), _opaque(opaque) {}
+ void response(AbstractProcessLoop& events_loop) {_proc(_opaque, (TimerID)this);}
+
+private:
+ timer_proc_t _proc;
+ void* _opaque;
+};
+
+TimerID Platform::create_interval_timer(timer_proc_t proc, void* opaque)
+{
+ return (TimerID)(new PlatformTimer(proc, opaque));
+}
+
+bool Platform::activate_interval_timer(TimerID timer, unsigned int millisec)
+{
+ ASSERT(main_loop);
+ main_loop->activate_interval_timer((PlatformTimer*)timer, millisec);
+ return true;
+}
+
+bool Platform::deactivate_interval_timer(TimerID timer)
+{
+ ASSERT(main_loop);
+ main_loop->deactivate_interval_timer((PlatformTimer*)timer);
+ return true;
+}
+
+void Platform::destroy_interval_timer(TimerID timer)
+{
+ deactivate_interval_timer(timer);
+ ((PlatformTimer*)timer)->unref();
+}