Patches 7-9 from Petteri Aimonen

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5365 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2012-11-17 13:50:02 +00:00
parent 0cf7957311
commit ecda1b2df0
6 changed files with 86 additions and 264 deletions

View File

@ -206,4 +206,10 @@
Contributed by Petteri, Aimonen.
* NxWM::CStartWindow: Fix mq_receive error handling with signal is recieved.
From Petteri Aimonen.
* NxWidgets:CNxTimer: Replace the original (apparently non-functional) signal-
based solution with a work queue-based solution. This raises some isses about
using the internal work queues from user space. I have decided to implemented
user-space work queues (someday) in order to accomplish that functionaliy.
Submitted by Petteri Aimonen.
solutions

View File

@ -201,6 +201,12 @@ namespace NXWidgets
virtual inline ~CImage() { }
/**
* Get pointer to the bitmap that this image contains.
*/
inline FAR IBitmap *getBitmap() const { return m_bitmap; }
/**
* Insert the dimensions that this widget wants to have into the rect
* passed in as a parameter. All coordinates are relative to the

View File

@ -80,6 +80,8 @@
#include <stdbool.h>
#include <ctime>
#include <nuttx/wqueue.h>
#include "cnxwidget.hxx"
/****************************************************************************
@ -108,42 +110,18 @@ namespace NXWidgets
class CNxTimer : public CNxWidget
{
protected:
FAR timer_t m_timerid; /**< POSIX timer */
struct work_s m_work; /**< Work queue entry */
uint32_t m_timeout; /**< The timeout value in milliseconds */
bool m_isRunning; /**< Indicates whether or not the timer is running */
bool m_isRepeater; /**< Indicates whether or not the timer repeats */
/**
* The SIGALM signal handler that will be called when the timer goes off
* Static function called from work queue when the timeout expires.
*
* @param signo The signal number call caused the handler to run (SIGALM)
* @param arg Pointer to the CNxTimer instance.
*/
static void signalHandler(int signo);
/**
* Handle an expired timer
*/
void handleTimerExpiration(void);
/**
* Convert a timespec to milliseconds
*
* @param tp The pointer to the timespec to convert
* @return The corresponding time in milliseconds
*/
uint32_t timespecToMilliseconds(FAR const struct timespec *tp);
/**
* Convert milliseconds to a timespec
*
* @param milliseconds The milliseconds to be converted
* @param tp The pointer to the location to store the converted timespec
*/
void millisecondsToTimespec(uint32_t milliseconds, FAR struct timespec *tp);
static void workQueueCallback(FAR void *arg);
/**
* Copy constructor is protected to prevent usage.
@ -171,15 +149,6 @@ namespace NXWidgets
~CNxTimer(void);
/**
* Return the time remaining on this timer.
*
* @return The number of milliseconds that this timer runs before
* firing an event. Zero is returned if the timer is not running.
*/
const uint32_t getTimeout(void);
/**
* Resets the (running) timer to its initial timeout value. This
* call does nothing if the timer is not running.
@ -212,6 +181,18 @@ namespace NXWidgets
{
m_timeout = timeout;
}
/**
* Return the timeout of this timer.
*
* @return The number of milliseconds that this timer will run before
* firing an event.
*/
inline uint32_t getTimeout(void) const
{
return m_timeout;
}
};
}

View File

@ -77,11 +77,13 @@
#include <stdbool.h>
#include <cstring>
#include <ctime>
#include <csignal>
#include <debug.h>
#include <errno.h>
#include <nuttx/clock.h>
#include <nuttx/wqueue.h>
#include "cnxtimer.hxx"
#include "singletons.hxx"
/****************************************************************************
* Pre-Processor Definitions
@ -116,44 +118,9 @@ CNxTimer::CNxTimer(CWidgetControl *pWidgetControl, uint32_t timeout, bool repeat
m_isRepeater = repeat;
m_isRunning = false;
// Create a POSIX timer (We can't do anything about failures here)
// Reset the work structure
int ret = timer_create(CLOCK_REALTIME, (FAR struct sigevent *)NULL, &m_timerid);
if (ret < 0)
{
gdbg("timer_create() failed\n");
return;
}
// If we are the first timer created in the whole system, then create
// the timer list and attach the SIGALRM timer handler.
if (!g_nxTimers)
{
if (!g_nxTimers)
{
gdbg("Failed to create the timer list\n");
return;
}
// Attach the SIGALM signal handler (no harm if this is done multiple times)
struct sigaction sigact;
sigact.sa_handler = signalHandler;
sigact.sa_flags = 0;
sigemptyset(&sigact.sa_mask);
ret = sigaction(SIGALRM, &sigact, (FAR struct sigaction *)NULL);
if (ret < 0)
{
gdbg("sigaction() failed\n");
return;
}
}
// Add ourself onto the array of timers
#warning "Need to disable SIGALRM here"
g_nxTimers->push_back(this);
memset(&m_work, 0, sizeof(m_work));
}
/**
@ -162,54 +129,6 @@ CNxTimer::CNxTimer(CWidgetControl *pWidgetControl, uint32_t timeout, bool repeat
CNxTimer::~CNxTimer(void)
{
// Locate ourself in the list of timers and remove ourselves
#warning "Need to disable SIGALRM here"
for (int i = 0; i < g_nxTimers->size(); i++)
{
CNxTimer *timer = g_nxTimers->at(i);
if (timer == this)
{
g_nxTimers->erase(i);
break;
}
}
// Destroy the timer
(void)timer_delete(m_timerid);
}
/**
* Return the timeout of this timer.
*
* @return The number of milliseconds that this timer will run before firing
* an event.
*/
const uint32_t CNxTimer::getTimeout(void)
{
// If the timer is not running, then just return the timeout value
if (!m_isRunning)
{
return m_timeout;
}
else
{
// Get the time remaining on the POSIX timer. Of course, there
// are race conditions here.. the timer could expire at anytime
struct itimerspec remaining;
int ret = timer_gettime(m_timerid, &remaining);
if (ret < 0)
{
gdbg("timer_gettime() failed\n");
return 0;
}
return timespecToMilliseconds(&remaining.it_value);
}
}
/**
@ -222,11 +141,7 @@ void CNxTimer::reset(void)
if (m_isRunning)
{
// If the specified timer was already armed when timer_settime() is
// called, this call will reset the time until next expiration to the
// value specified.
m_isRunning = false;
stop();
start();
}
}
@ -241,24 +156,14 @@ void CNxTimer::start(void)
if (!m_isRunning)
{
// If the specified timer was already armed when timer_settime() is
// called, this call will reset the time until next expiration to the
// value specified.
uint32_t ticks = m_timeout / MSEC_PER_TICK;
int ret = work_queue(USRWORK, &m_work, workQueueCallback, this, ticks);
struct itimerspec timerspec;
millisecondsToTimespec(m_timeout, &timerspec.it_value);
timerspec.it_interval.tv_sec = 0;
timerspec.it_interval.tv_nsec = 0;
int ret = timer_settime(m_timerid, 0, &timerspec,
(FAR struct itimerspec *)NULL);
if (ret < 0)
{
gdbg("timer_settime() failed\n");
gdbg("work_queue failed: %d\n", ret);
}
// The timer is now running
m_isRunning = true;
}
}
@ -271,112 +176,33 @@ void CNxTimer::stop(void)
{
if (m_isRunning)
{
// If the it_value member of value is zero, the timer will be disarmed.
// The effect of disarming or resetting a timer with pending expiration
// notifications is unspecified.
int ret = work_cancel(USRWORK, &m_work);
struct itimerspec nullTime;
memset(&nullTime, 0, sizeof(struct itimerspec));
int ret = timer_settime(m_timerid, 0, &nullTime,
(FAR struct itimerspec *)NULL);
if (ret < 0)
{
gdbg("timer_settime failed\n");
gdbg("work_cancel failed: %d\n", ret);
}
// The time is no longer running
m_isRunning = false;
}
}
/**
* The SIGALM signal handler that will be called when the timer goes off
*
* @param signo The signal number call caused the handler to run (SIGALM)
*/
void CNxTimer::signalHandler(int signo)
void CNxTimer::workQueueCallback(FAR void *arg)
{
// Call handlerTimerExpiration on every timer instance
CNxTimer* This = (CNxTimer*)arg;
for (int i = 0; i < g_nxTimers->size(); i++)
This->m_isRunning = false;
// Raise the action event.
This->m_widgetEventHandlers->raiseActionEvent();
// Restart the timer if this is a repeating timer
if (This->m_isRepeater)
{
CNxTimer *timer = g_nxTimers->at(i);
timer->handleTimerExpiration();
This->start();
}
}
/**
* Handle an expired timer
*/
void CNxTimer::handleTimerExpiration(void)
{
// Do we think our timer is running?
if (m_isRunning)
{
// Is it running? It the timer is not running, it will return an
// it_value of zero.
struct itimerspec status;
int ret = timer_gettime(m_timerid, &status);
if (ret < 0)
{
gdbg("timer_gettime() failed\n");
return;
}
// it_value == 0 means that timer is not running
if (status.it_value.tv_sec == 0 && status.it_value.tv_nsec == 0)
{
// It has expired
m_isRunning = false;
// Raise the action event. Hmmm.. are there any issues with
// doing this from a signal handler? We'll find out
m_widgetEventHandlers->raiseActionEvent();
// Restart the timer if this is a repeating timer
if (m_isRepeater)
{
start();
}
}
}
}
/**
* Convert a timespec to milliseconds
*
* @param tp The pointer to the timespec to convert
* @return The corresponding time in milliseconds
*/
uint32_t CNxTimer::timespecToMilliseconds(FAR const struct timespec *tp)
{
return (uint32_t)tp->tv_sec * 1000 + (uint32_t)tp->tv_nsec / 10000000;
}
/**
* Convert milliseconds to a timespec
*
* @param milliseconds The milliseconds to be converted
* @param tp The pointer to the location to store the converted timespec
*/
void CNxTimer::millisecondsToTimespec(uint32_t milliseconds,
FAR struct timespec *tp)
{
tp->tv_sec = milliseconds / 1000;
uint32_t remainder = milliseconds - (uint32_t)tp->tv_sec * 1000;
tp->tv_nsec = remainder * 1000000;
}

View File

@ -101,6 +101,8 @@ CNxTkWindow::~CNxTkWindow(void)
// constructed-us.
(void)nxtk_closewindow(m_hNxTkWindow);
delete m_widgetControl;
}
/**

View File

@ -655,6 +655,7 @@ bool CTaskbar::stopApplication(IApplication *app)
// Yes.. found it. Delete the icon image and remove the entry
// from the list of applications
delete m_slots.at(i).image->getBitmap();
delete m_slots.at(i).image;
m_slots.erase(i);
break;