/* 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 . */ #ifndef _H_PROCESS_LOOP #define _H_PROCESS_LOOP #include "common.h" #include #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: void set_generation(uint32_t gen) { _generation = gen;} uint32_t get_generation() { return _generation;} 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 _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;} void calc_next_expiration_time(uint64_t now); 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 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(); /* can be used for handling timers in modal loop state in Windows (mainly, for updating the screen) */ int get_soonest_timeout(); void timers_action(); 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