Commit 7a2f9b44 authored by Antônio Augusto Fröhlich's avatar Antônio Augusto Fröhlich
Browse files

Solving exercise about the alarm mechanism

parent 39d12aef
......@@ -14,23 +14,20 @@ __BEGIN_SYS
class Alarm
{
public:
typedef TSC::Time_Stamp Time_Stamp;
private:
typedef TSC::Hertz Hertz;
typedef Timer::Tick Tick;
typedef Relative_Queue<Alarm, Tick> Queue;
public:
typedef RTC::Microsecond Microsecond;
// An alarm handler
typedef Function_Handler Handler;
// Infinite times (for alarms)
enum { INFINITE = -1 };
private:
typedef Relative_Queue<Alarm, Tick> Queue;
public:
Alarm(const Microsecond & time, Handler handler, int times = 1);
Alarm(const Microsecond & time, Handler * handler, int times = 1);
~Alarm();
static Hertz frequency() { return _timer->frequency(); }
......@@ -55,13 +52,13 @@ private:
private:
Tick _ticks;
Handler _handler;
Handler * _handler;
int _times;
Queue::Element _link;
static Alarm_Timer * _timer;
static volatile Tick _elapsed;
static Queue _requests;
static Queue _request;
};
class Delay
......
......@@ -3,6 +3,7 @@
#ifndef __condition_h
#define __condition_h
#include <utility/handler.h>
#include <synchronizer.h>
__BEGIN_SYS
......@@ -112,6 +113,20 @@ public:
// volatile int _time_stamp;
// };
// An event handler that triggers a condition variable (see handler.h)
class Condition_Handler: public Handler
{
public:
Condition_Handler(Condition * h) : _handler(h) {}
~Condition_Handler() {}
void operator()() { _handler->signal(); }
private:
Condition * _handler;
};
__END_SYS
#endif
......
......@@ -3,6 +3,7 @@
#ifndef __mutex_h
#define __mutex_h
#include <utility/handler.h>
#include <synchronizer.h>
__BEGIN_SYS
......@@ -20,6 +21,20 @@ private:
volatile bool _locked;
};
// An event handler that triggers a mutex (see handler.h)
class Mutex_Handler: public Handler
{
public:
Mutex_Handler(Mutex * h) : _handler(h) {}
~Mutex_Handler() {}
void operator()() { _handler->unlock(); }
private:
Mutex * _handler;
};
__END_SYS
#endif
......@@ -3,6 +3,7 @@
#ifndef __semaphore_h
#define __semaphore_h
#include <utility/handler.h>
#include <synchronizer.h>
__BEGIN_SYS
......@@ -21,6 +22,19 @@ private:
};
// An event handler that triggers a semaphore (see handler.h)
class Semaphore_Handler: public Handler
{
public:
Semaphore_Handler(Semaphore * h) : _handler(h) {}
~Semaphore_Handler() {}
void operator()() { _handler->v(); }
private:
Semaphore * _handler;
};
__END_SYS
#endif
......@@ -5,6 +5,7 @@
#include <system/kmalloc.h>
#include <utility/queue.h>
#include <utility/handler.h>
#include <cpu.h>
#include <machine.h>
......@@ -175,7 +176,7 @@ protected:
Thread * volatile _joining;
Queue::Element _link;
static Spin _lock;
static volatile unsigned int _thread_count;
static Scheduler_Timer * _timer;
private:
......@@ -184,6 +185,20 @@ private:
static Queue _suspended;
};
// An event handler that triggers a thread (see handler.h)
class Thread_Handler : public Handler
{
public:
Thread_Handler(Thread * h) : _handler(h) {}
~Thread_Handler() {}
void operator()() { _handler->resume(); }
private:
Thread * _handler;
};
__END_SYS
#endif
......@@ -7,7 +7,47 @@
__BEGIN_SYS
typedef void (* Function_Handler)();
class Handler
{
public:
// A handler function
typedef void (Function)();
public:
Handler() {}
virtual ~Handler() {}
virtual void operator()() = 0;
void operator delete(void * object) {}
};
class Function_Handler: public Handler
{
public:
Function_Handler(Function * h): _handler(h) {}
~Function_Handler() {}
void operator()() { _handler(); }
private:
Function * _handler;
};
template<typename T>
class Functor_Handler: public Handler
{
public:
typedef void (Functor)(T *);
Functor_Handler(Functor * h, T * p): _handler(h), _ptr(p) {}
~Functor_Handler() {}
void operator()() { _handler(_ptr); }
private:
Functor * _handler;
T * _ptr;
};
__END_SYS
......
......@@ -9,11 +9,12 @@ __BEGIN_SYS
// Class attributes
Alarm_Timer * Alarm::_timer;
volatile Alarm::Tick Alarm::_elapsed;
Alarm::Queue Alarm::_requests;
Alarm::Queue Alarm::_request;
// Methods
Alarm::Alarm(const Microsecond & time, Handler handler, int times):
_ticks(ticks(time)), _handler(handler), _times(times), _link(this, _ticks)
Alarm::Alarm(const Microsecond & time, Handler * handler, int times):
_ticks(ticks(time)), _handler(handler), _times(times), _link(this, _ticks)
{
lock();
......@@ -23,81 +24,76 @@ Alarm::Alarm(const Microsecond & time, Handler handler, int times):
<< ",x=" << times << ") => " << this << "\n";
if(_ticks) {
_requests.insert(&_link);
_request.insert(&_link);
unlock();
} else {
unlock();
handler();
(*handler)();
}
}
Alarm::~Alarm()
{
lock();
db<Alarm>(TRC) << "~Alarm()\n";
db<Alarm>(TRC) << "~Alarm(this=" << this << ")\n";
_requests.remove(this);
_request.remove(this);
unlock();
}
// Class methods
void Alarm::delay(const Microsecond & time)
{
db<Alarm>(TRC) << "Alarm::delay(time=" << time << ")\n";
lock();
Tick t = _elapsed + ticks(time);
db<Alarm>(TRC) << "Alarm::delay(time=" << time << ")\n";
while(_elapsed < t);
Semaphore semaphore(0);
Semaphore_Handler handler(&semaphore);
Alarm alarm(time, &handler, 1); // if time < tick trigger v()
semaphore.p();
unlock();
}
void Alarm::handler()
{
static Tick next_tick;
static Handler next_handler;
lock();
_elapsed++;
if(Traits<Alarm>::visible) {
Display display;
int lin, col;
display.position(&lin, &col);
display.position(0, 79);
display.putc(_elapsed);
display.position(lin, col);
}
Alarm * alarm = 0;
if(next_tick)
next_tick--;
if(!next_tick) {
if(next_handler) {
db<Alarm>(TRC) << "Alarm::handler(h="
<< reinterpret_cast<void *>(next_handler) << ")\n";
unlock();
next_handler();
lock();
}
if(_requests.empty())
next_handler = 0;
else {
Queue::Element * e = _requests.remove();
Alarm * alarm = e->object();
next_tick = alarm->_ticks;
next_handler = alarm->_handler;
if(alarm->_times != -1)
if(!_request.empty()) {
if(_request.head()->promote() <= 0) { // rank can be negative whenever
// multiple handlers get created
// for the same time tick
Queue::Element * e = _request.remove();
alarm = e->object();
if(alarm->_times != INFINITE)
alarm->_times--;
if(alarm->_times) {
e->rank(alarm->_ticks);
_requests.insert(e);
_request.insert(e);
}
}
}
unlock();
if(alarm) {
db<Alarm>(TRC) << "Alarm::handler(this=" << alarm << ", h="
<< reinterpret_cast<void*>(alarm->handler)
<< ")\n";
(*alarm->_handler)();
}
}
__END_SYS
......@@ -19,9 +19,11 @@ int main()
cout << "I'm the first thread of the first task created in the system.\n";
cout << "I'll now create two alarms and put myself in a delay ...\n";
Alarm alarm_a(1000000, &func_a, iterations);
Function_Handler handler_a(&func_a);
Alarm alarm_a(1000000, &handler_a, iterations);
Alarm alarm_b(1000000, &func_b, iterations);
Function_Handler handler_b(&func_b);
Alarm alarm_b(1000000, &handler_b, iterations);
// Note that in case of idle-waiting, this thread will go into suspend
// and the alarm handlers above will trigger the functions in the context
......
......@@ -8,7 +8,7 @@
__BEGIN_SYS
// Class attributes
Spin Thread::_lock;
volatile unsigned int Thread::_thread_count;
Scheduler_Timer * Thread::_timer;
Thread* volatile Thread::_running;
......@@ -30,6 +30,8 @@ void Thread::common_constructor(Log_Addr entry, unsigned int stack_size)
<< "},context={b=" << _context
<< "," << *_context << "}) => " << this << "\n";
_thread_count++;
switch(_state) {
case RUNNING: break;
case SUSPENDED: _suspended.insert(&_link); break;
......@@ -50,6 +52,9 @@ Thread::~Thread()
<< ",context={b=" << _context
<< "," << *_context << "})\n";
if(_state != FINISHING)
_thread_count--;
_ready.remove(this);
_suspended.remove(this);
......@@ -165,6 +170,8 @@ void Thread::exit(int status)
prev->_state = FINISHING;
*static_cast<int *>(prev->_stack) = status;
_thread_count--;
if(prev->_joining) {
prev->_joining->resume();
prev->_joining = 0;
......@@ -251,16 +258,23 @@ void Thread::implicit_exit()
int Thread::idle()
{
while(true) {
db<Thread>(TRC) << "Thread::idle()\n";
CPU::int_enable();
if(Traits<Thread>::trace_idle)
db<Thread>(TRC) << "Thread::idle()\n";
if(_ready.empty() && _suspended.empty()) {
if(_thread_count <= 1) { // Only idle is left
CPU::int_disable();
db<Thread>(WRN) << "The last thread has exited!\n";
db<Thread>(WRN) << "Rebooting the machine ...\n";
Machine::reboot();
} else
if(reboot) {
db<Thread>(WRN) << "Rebooting the machine ...\n";
Machine::reboot();
} else {
db<Thread>(WRN) << "Halting the machine ...\n";
CPU::halt();
}
} else {
CPU::int_enable();
CPU::halt();
}
}
return 0;
......
// EPOS Event Handler Utility Test Program
#include <utility/ostream.h>
#include <utility/handler.h>
#include <alarm.h>
#include <thread.h>
#include <semaphore.h>
#include <chronometer.h>
__USING_SYS
const int iterations = 100;
const int period_a = 100;
const int period_b = 200;
const int period_c = 300;
void func_a(void);
int func_b(void);
int func_c(void);
int max(int a, int b, int c) { return ((a >= b) && (a >= c)) ? a : ((b >= a) && (b >= c) ? b : c); }
OStream cout;
Semaphore sem_c(0);
Thread * thread_b;
Thread * thread_c;
int main()
{
cout << "Event Handler Utility Test\n";
cout << "\nThis test consists in creating three event handlers as follows:\n";
cout << " Handler 1 triggers a \"function\" that prints an \"a\" every " << period_a << " ms;\n";
cout << " Handler 2 triggers a \"thread\" that prints a \"b\" every " << period_b << " ms;\n";
cout << " Handler 3 triggers a \"v\" on a \"semaphore\" that controls another thread that prints a \"c\" every " << period_c << "ms.\n";
thread_b = new Thread(&func_b);
thread_c = new Thread(&func_c);
cout << "Threads B and C have been created!\n";
Function_Handler handler_a(&func_a);
Thread_Handler handler_b(thread_b);
Semaphore_Handler handler_c(&sem_c);
cout << "Now the alarms will be created, along with a chronometer to keep track of the total execution time. I'll then wait for the threads to finish...\n\n";
Chronometer chrono;
chrono.start();
Alarm alarm_a(period_a * 1000, &handler_a, iterations);
Alarm alarm_b(period_b * 1000, &handler_b, iterations);
Alarm alarm_c(period_c * 1000, &handler_c, iterations);
int status_b = thread_b->join();
int status_c = thread_c->join();
chrono.stop();
cout << "\n\nThread B exited with status " << status_b
<< " and thread C exited with status " << status_c << "\n";
cout << "\nThe estimated time to run the test was " << max(period_a, period_b, period_c) * iterations << " ms. The measured time was " << chrono.read() / 1000 <<" ms!\n";
delete thread_b;
delete thread_c;
cout << "I'm also done, bye!\n";
return 0;
}
void func_a()
{
cout << "a";
return;
}
int func_b(void)
{
cout << "B";
for(int i = 0; i < iterations; i++) {
thread_b->suspend();
cout << "b";
}
cout << "B";
return 'B';
}
int func_c(void)
{
cout << "C";
for(int i = 0; i < iterations; i++) {
sem_c.p();
cout << "c";
}
cout << "C";
return 'C';
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment