Remote control uses threads

This commit is contained in:
Klaus Schmidinger 2000-10-08 09:25:20 +02:00
parent 60958ab132
commit 97c3bb6148
11 changed files with 417 additions and 158 deletions

View File

@ -4,13 +4,13 @@
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
#
# $Id: Makefile 1.12 2000/10/01 14:27:12 kls Exp $
# $Id: Makefile 1.13 2000/10/07 16:24:08 kls Exp $
DVBDIR = ../DVB
INCLUDES = -I$(DVBDIR)/driver
OBJS = config.o dvbapi.o dvbosd.o eit.o font.o interface.o menu.o osd.o\
recording.o remote.o svdrp.o tools.o vdr.o videodir.o
recording.o remote.o svdrp.o thread.o tools.o vdr.o videodir.o
OSDFONT = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-1
@ -40,12 +40,13 @@ dvbapi.o : dvbapi.c config.h dvbapi.h dvbosd.h font.h interface.h svdrp.h tool
dvbosd.o : dvbosd.c dvbosd.h font.h tools.h
eit.o : eit.c eit.h tools.h
font.o : font.c font.h fontosd.c tools.h
interface.o: interface.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h tools.h
interface.o: interface.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h
menu.o : menu.c config.h dvbapi.h dvbosd.h font.h interface.h menu.h osd.h recording.h svdrp.h tools.h
osd.o : osd.c config.h dvbapi.h dvbosd.h font.h interface.h osd.h svdrp.h tools.h
recording.o: recording.c config.h dvbapi.h dvbosd.h font.h interface.h recording.h svdrp.h tools.h videodir.h
remote.o : remote.c config.h dvbapi.h dvbosd.h font.h remote.h tools.h
remote.o : remote.c config.h dvbapi.h dvbosd.h font.h remote.h thread.h tools.h
svdrp.o : svdrp.c config.h dvbapi.h dvbosd.h font.h interface.h svdrp.h tools.h
thread.o : thread.c thread.h
tools.o : tools.c tools.h
vdr.o : vdr.c config.h dvbapi.h dvbosd.h font.h interface.h menu.h osd.h recording.h svdrp.h tools.h videodir.h
videodir.o : videodir.c tools.h videodir.h
@ -53,7 +54,7 @@ videodir.o : videodir.c tools.h videodir.h
# The main program:
vdr: $(OBJS)
g++ -g -O2 $(OBJS) -lncurses -ljpeg -o vdr
g++ -g -O2 $(OBJS) -lncurses -ljpeg -lpthread -o vdr
# The font file:

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: config.h 1.22 2000/10/01 14:14:18 kls Exp $
* $Id: config.h 1.23 2000/10/07 17:34:23 kls Exp $
*/
#ifndef __CONFIG_H
@ -17,7 +17,7 @@
#include "dvbapi.h"
#include "tools.h"
#define VDRVERSION "0.65"
#define VDRVERSION "0.66"
#define MaxBuffer 10000

View File

@ -4,10 +4,11 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: dvbosd.c 1.2 2000/10/03 13:34:13 kls Exp $
* $Id: dvbosd.c 1.3 2000/10/07 14:42:48 kls Exp $
*/
#include "dvbosd.h"
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/unistd.h>
@ -138,11 +139,16 @@ void cDvbOsd::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, co
dc.x1 = x1;
dc.y1 = y1;
dc.data = (void *)data;
// must block all signals, otherwise the command might not be fully executed
sigset_t set, oldset;
sigfillset(&set);
sigprocmask(SIG_BLOCK, &set, &oldset);
ioctl(videoDev, VIDIOCSOSDCOMMAND, &dc);
usleep(10); // XXX Workaround for a driver bug (cInterface::DisplayChannel() displayed texts at wrong places
// XXX and sometimes the OSD was no longer displayed).
// XXX Increase the value if the problem still persists on your particular system.
// TODO Check if this is still necessary with driver versions after 0.7.
sigprocmask(SIG_SETMASK, &oldset, NULL);
}
}

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: interface.c 1.21 2000/10/03 13:28:02 kls Exp $
* $Id: interface.c 1.22 2000/10/07 16:42:37 kls Exp $
*/
#include "interface.h"
@ -60,17 +60,16 @@ void cInterface::Close(void)
unsigned int cInterface::GetCh(bool Wait)
{
if (RcIo.InputAvailable(Wait)) {
unsigned int Command;
return RcIo.GetCommand(&Command, NULL) ? Command : 0;
}
return 0;
if (open)
cDvbApi::PrimaryDvbApi->Flush();
if (!RcIo.InputAvailable())
cFile::AnyFileReady(-1, Wait ? 1000 : 0);
unsigned int Command;
return RcIo.GetCommand(&Command) ? Command : 0;
}
eKeys cInterface::GetKey(bool Wait)
{
if (open)
cDvbApi::PrimaryDvbApi->Flush();
if (SVDRP)
SVDRP->Process();
eKeys Key = keyFromWait != kNone ? keyFromWait : Keys.Get(GetCh(Wait));
@ -85,12 +84,15 @@ void cInterface::PutKey(eKeys Key)
eKeys cInterface::Wait(int Seconds, bool KeepChar)
{
eKeys Key = kNone;
if (open)
cDvbApi::PrimaryDvbApi->Flush();
RcIo.Flush(500);
if (cFile::AnyFileReady(-1, Seconds * 1000))
Key = GetKey();
eKeys Key = kNone;
time_t timeout = time(NULL) + Seconds;
for (;;) {
Key = GetKey();
if (Key != kNone || time(NULL) > timeout)
break;
}
if (KeepChar)
keyFromWait = Key;
return Key;
@ -220,9 +222,11 @@ void cInterface::Help(const char *Red, const char *Green, const char *Yellow, co
void cInterface::QueryKeys(void)
{
Keys.Clear();
Clear();
WriteText(1, 1, "Learning Remote Control Keys");
WriteText(1, 3, "Phase 1: Detecting RC code type");
WriteText(1, 5, "Press any key on the RC unit");
cDvbApi::PrimaryDvbApi->Flush();
#ifndef REMOTE_KBD
unsigned char Code = 0;
unsigned short Address;
@ -238,9 +242,11 @@ void cInterface::QueryKeys(void)
Keys.address = Address;
WriteText(1, 5, "RC code detected!");
WriteText(1, 6, "Do not press any key...");
cDvbApi::PrimaryDvbApi->Flush();
RcIo.Flush(3000);
ClearEol(0, 5);
ClearEol(0, 6);
cDvbApi::PrimaryDvbApi->Flush();
break;
}
#endif

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: interface.h 1.13 2000/09/18 22:29:31 kls Exp $
* $Id: interface.h 1.14 2000/10/07 16:17:53 kls Exp $
*/
#ifndef __INTERFACE_H
@ -38,7 +38,7 @@ public:
void ClearEol(int x, int y, eDvbColor Color = clrBackground);
void SetCols(int *c);
void Write(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground);
void WriteText(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBlack);
void WriteText(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground);
void Title(const char *s);
void Status(const char *s, eDvbColor FgColor = clrBlack, eDvbColor BgColor = clrCyan);
void Info(const char *s);

293
remote.c
View File

@ -6,7 +6,7 @@
*
* Ported to LIRC by Carsten Koch <Carsten.Koch@icem.de> 2000-06-16.
*
* $Id: remote.c 1.15 2000/10/03 10:49:58 kls Exp $
* $Id: remote.c 1.16 2000/10/08 09:25:20 kls Exp $
*/
#include "remote.h"
@ -27,16 +27,11 @@
#include "config.h"
#include "tools.h"
#define REPEATLIMIT 100 // ms
#define REPEATDELAY 250 // ms
// --- cRcIoBase -------------------------------------------------------------
cRcIoBase::cRcIoBase(void)
{
t = 0;
firstTime = lastTime = 0;
lastCommand = 0;
}
cRcIoBase::~cRcIoBase()
@ -69,12 +64,12 @@ void cRcIoKBD::Flush(int WaitMs)
}
}
bool cRcIoKBD::InputAvailable(bool Wait)
bool cRcIoKBD::InputAvailable(void)
{
return f.Ready(Wait);
return f.Ready(false);
}
bool cRcIoKBD::GetCommand(unsigned int *Command, unsigned short *)
bool cRcIoKBD::GetCommand(unsigned int *Command)
{
if (Command) {
*Command = getch();
@ -87,36 +82,119 @@ bool cRcIoKBD::GetCommand(unsigned int *Command, unsigned short *)
#elif defined REMOTE_RCU
#define REPEATLIMIT 20 // ms
#define REPEATDELAY 350 // ms
cRcIoRCU::cRcIoRCU(char *DeviceName)
{
dp = 0;
mode = modeB;
code = 0;
address = 0xFFFF;
receivedAddress = 0;
receivedCommand = 0;
receivedData = receivedRepeat = false;
lastNumber = 0;
if (f.Open(DeviceName, O_RDWR | O_NONBLOCK)) {
if ((f = open(DeviceName, O_RDWR | O_NONBLOCK)) >= 0) {
struct termios t;
if (tcgetattr(f, &t) == 0) {
cfsetspeed(&t, B9600);
cfmakeraw(&t);
if (tcsetattr(f, TCSAFLUSH, &t) == 0)
if (tcsetattr(f, TCSAFLUSH, &t) == 0) {
Start();
return;
}
}
LOG_ERROR_STR(DeviceName);
f.Close();
close(f);
}
else
LOG_ERROR_STR(DeviceName);
f = -1;
}
cRcIoRCU::~cRcIoRCU()
{
}
int cRcIoRCU::ReceiveByte(bool Wait)
void cRcIoRCU::Action(void)
{
#pragma pack(1)
union {
struct {
unsigned short address;
unsigned int command;
} data;
unsigned char raw[6];
} buffer;
#pragma pack()
dsyslog(LOG_INFO, "RCU remote control thread started (pid=%d)", getpid());
unsigned int LastCommand = 0;
int FirstTime = 0;
for (; f >= 0;) {
LOCK_THREAD;
if (ReceiveByte(REPEATLIMIT) == 'X') {
for (int i = 0; i < 6; i++) {
int b = ReceiveByte();
if (b >= 0) {
buffer.raw[i] = b;
if (i == 5) {
unsigned short Address = ntohs(buffer.data.address); // the PIC sends bytes in "network order"
unsigned int Command = ntohl(buffer.data.command);
if (code == 'B' && address == 0x0000 && Command == 0x00004000)
// Well, well, if it isn't the "d-box"...
// This remote control sends the above command before and after
// each keypress - let's just drop this:
break;
int Now = time_ms();
if (Command != LastCommand) {
receivedAddress = Address;
receivedCommand = Command;
receivedData = true;
FirstTime = Now;
}
else {
if (Now - FirstTime < REPEATDELAY)
break; // repeat function kicks in after a short delay
receivedData = receivedRepeat = true;
}
LastCommand = Command;
WakeUp();
}
}
else
break;
}
}
else if (receivedData) { // the last data before releasing the key hasn't been fetched yet
if (receivedRepeat) { // it was a repeat, so let's drop it
//XXX replace it with "released"???
receivedData = receivedRepeat = false;
LastCommand = 0;
//XXX WakeUp();
}
}
else if (receivedRepeat) { // all data has already been fetched, but the last one was a repeat
//XXX replace it with "released"???
//XXX receivedData = true;
receivedRepeat = false;
LastCommand = 0;
WakeUp();
}
else
LastCommand = 0;
}
}
int cRcIoRCU::ReceiveByte(int TimeoutMs)
{
// Returns the byte if one was received within a timeout, -1 otherwise
if (InputAvailable(Wait)) {
if (cFile::FileReady(f, TimeoutMs)) {
unsigned char b;
if (read(f, &b, 1) == 1)
return b;
@ -128,16 +206,16 @@ int cRcIoRCU::ReceiveByte(bool Wait)
bool cRcIoRCU::SendByteHandshake(unsigned char c)
{
if (f.IsOpen()) {
if (f >= 0) {
int w = write(f, &c, 1);
if (w == 1) {
for (int reply = ReceiveByte(); reply >= 0;) {
for (int reply = ReceiveByte(REPEATLIMIT); reply >= 0;) {
if (reply == c)
return true;
else if (reply == 'X') {
// skip any incoming RC code - it will come again
for (int i = 6; i--;) {
if (ReceiveByte(false) < 0)
if (ReceiveByte() < 0)
return false;
}
}
@ -152,6 +230,8 @@ bool cRcIoRCU::SendByteHandshake(unsigned char c)
bool cRcIoRCU::SendByte(unsigned char c)
{
LOCK_THREAD;
for (int retry = 5; retry--;) {
if (SendByteHandshake(c))
return true;
@ -174,66 +254,31 @@ bool cRcIoRCU::SetMode(unsigned char Mode)
void cRcIoRCU::Flush(int WaitMs)
{
int t0 = time_ms();
LOCK_THREAD;
int t0 = time_ms();
for (;;) {
while (ReceiveByte(false) >= 0)
while (ReceiveByte() >= 0)
t0 = time_ms();
if (time_ms() - t0 >= WaitMs)
break;
}
receivedData = receivedRepeat = false;
}
bool cRcIoRCU::InputAvailable(bool Wait)
bool cRcIoRCU::GetCommand(unsigned int *Command)
{
return f.Ready(Wait);
}
if (receivedData) { // first we check the boolean flag without a lock, to avoid delays
bool cRcIoRCU::GetCommand(unsigned int *Command, unsigned short *Address)
{
#pragma pack(1)
union {
struct {
unsigned short address;
unsigned int command;
} data;
unsigned char raw[6];
} buffer;
#pragma pack()
Flush();
if (Command && ReceiveByte() == 'X') {
for (int i = 0; i < 6; i++) {
int b = ReceiveByte(false);
if (b >= 0)
buffer.raw[i] = b;
else
return false;
}
if (Address)
*Address = ntohs(buffer.data.address); // the PIC sends bytes in "network order"
else if (address != ntohs(buffer.data.address))
return false;
*Command = ntohl(buffer.data.command);
if (code == 'B' && address == 0x0000 && *Command == 0x00004000)
// Well, well, if it isn't the "d-box"...
// This remote control sends the above command before and after
// each keypress - let's just drop this:
return false;
if (*Command == lastCommand) {
// let's have a timeout to avoid getting overrun by commands
int now = time_ms();
int delta = now - lastTime;
lastTime = now;
if (delta < REPEATLIMIT) { // if commands come in rapidly...
if (now - firstTime < REPEATDELAY)
return false; // ...repeat function kicks in after a short delay
return true;
}
LOCK_THREAD;
if (receivedData) { // need to check again, since the status might have changed while waiting for the lock
if (Command)
*Command = receivedCommand;
//XXX repeat!!!
receivedData = false;
return true;
}
lastTime = firstTime = time_ms();
lastCommand = *Command;
return true;
}
if (time(NULL) - t > 60) {
SendCommand(code); // in case the PIC listens to the wrong code
@ -254,6 +299,8 @@ bool cRcIoRCU::Digit(int n, int v)
bool cRcIoRCU::Number(int n, bool Hex)
{
LOCK_THREAD;
if (!Hex) {
char buf[8];
sprintf(buf, "%4d", n & 0xFFFF);
@ -275,6 +322,8 @@ bool cRcIoRCU::Number(int n, bool Hex)
bool cRcIoRCU::String(char *s)
{
LOCK_THREAD;
const char *chars = mode == modeH ? "0123456789ABCDEF" : "0123456789-EHLP ";
int n = 0;
@ -318,8 +367,11 @@ bool cRcIoRCU::DetectCode(unsigned char *Code, unsigned short *Address)
sprintf(buf, "C0D%c", *Code);
String(buf);
SetCode(*Code, 0);
unsigned int Command;
if (GetCommand(&Command, Address)) {
delay_ms(REPEATDELAY);
receivedData = receivedRepeat = 0;
delay_ms(REPEATDELAY);
if (GetCommand()) {
*Address = receivedAddress;
SetMode(modeB);
String("----");
return true;
@ -337,77 +389,90 @@ bool cRcIoRCU::DetectCode(unsigned char *Code, unsigned short *Address)
#elif defined REMOTE_LIRC
#define REPEATLIMIT 20 // ms
#define REPEATDELAY 350 // ms
cRcIoLIRC::cRcIoLIRC(char *DeviceName)
{
repeat = 1;
*keyName = 0;
receivedData = receivedRepeat = false;
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, DeviceName);
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock >= 0) {
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) >= 0) {
f.Open(sock);
if ((f = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0) {
if (connect(f, (struct sockaddr *)&addr, sizeof(addr)) >= 0) {
Start();
return;
}
LOG_ERROR_STR(DeviceName);
close(sock);
close(f);
}
else
LOG_ERROR_STR(DeviceName);
f = -1;
}
cRcIoLIRC::~cRcIoLIRC()
{
}
const char *cRcIoLIRC::ReceiveString(void)
void cRcIoLIRC::Action(void)
{
int oldrepeat = 1;
dsyslog(LOG_INFO, "LIRC remote control thread started (pid=%d)", getpid());
if (repeat != 0) {
Flush();
if (repeat != 0) {
oldrepeat = repeat;
Flush(REPEATLIMIT);
}
}
if (repeat == 0) {
firstTime = time_ms();
repeat = 1;
return keyName;
}
if ((repeat > 1) && (repeat != oldrepeat) && (time_ms() > firstTime + REPEATDELAY)) {
repeat = 1;
return keyName;
}
return NULL;
}
void cRcIoLIRC::Flush(int WaitMs)
{
int FirstTime = 0;
char buf[LIRC_BUFFER_SIZE];
int t0 = time_ms();
do {
if (InputAvailable(false) && (read(f, buf, sizeof(buf)) > 21))
sscanf(buf, "%*x %x %7s", &repeat, keyName); // '7' in '%7s' is LIRC_KEY_BUF-1!
} while ((repeat != 0) && (time_ms() < t0 + WaitMs));
for (; f >= 0;) {
LOCK_THREAD;
if (cFile::FileReady(f, REPEATLIMIT) && read(f, buf, sizeof(buf)) > 21) {
int count;
sscanf(buf, "%*x %x %7s", &count, keyName); // '7' in '%7s' is LIRC_KEY_BUF-1!
int Now = time_ms();
if (count == 0) {
receivedData = true;
FirstTime = Now;
}
else {
if (Now - FirstTime < REPEATDELAY)
continue; // repeat function kicks in after a short delay
receivedData = receivedRepeat = true;
}
WakeUp();
}
else if (receivedData) { // the last data before releasing the key hasn't been fetched yet
if (receivedRepeat) { // it was a repeat, so let's drop it
//XXX replace it with "released"???
receivedData = receivedRepeat = false;
*keyName = 0;
//XXX WakeUp();
}
}
else if (receivedRepeat) { // all data has already been fetched, but the last one was a repeat
//XXX replace it with "released"???
//XXX receivedData = true;
receivedRepeat = false;
*keyName = 0;
WakeUp();
}
else
*keyName = 0;
}
}
bool cRcIoLIRC::InputAvailable(bool Wait)
bool cRcIoLIRC::GetCommand(unsigned int *Command)
{
return f.Ready(Wait);
}
if (receivedData) { // first we check the boolean flag without a lock, to avoid delays
bool cRcIoLIRC::GetCommand(unsigned int *Command, unsigned short *)
{
if (Command) {
const char *cmd = ReceiveString();
if (cmd) {
*Command = Keys.Encode(cmd);
LOCK_THREAD;
if (receivedData) { // need to check again, since the status might have changed while waiting for the lock
if (Command)
*Command = Keys.Encode(keyName);
//XXX repeat!!!
receivedData = false;
return true;
}
}

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: remote.h 1.10 2000/10/03 10:45:35 kls Exp $
* $Id: remote.h 1.11 2000/10/07 18:50:51 kls Exp $
*/
#ifndef __REMOTE_H
@ -12,13 +12,12 @@
#include <stdio.h>
#include <time.h>
#include "thread.h"
#include "tools.h"
class cRcIoBase {
protected:
time_t t;
int firstTime, lastTime;
unsigned int lastCommand;
cRcIoBase(void);
virtual ~cRcIoBase();
public:
@ -29,9 +28,9 @@ public:
virtual void SetPoints(unsigned char Dp, bool On) {}
virtual bool String(char *s) { return true; }
virtual bool DetectCode(unsigned char *Code, unsigned short *Address) { return true; }
virtual void Flush(int WaitMs = 0) = 0;
virtual bool InputAvailable(bool Wait = false) = 0;
virtual bool GetCommand(unsigned int *Command, unsigned short *Address = NULL) = 0;
virtual void Flush(int WaitMs = 0) {}
virtual bool InputAvailable(void) = 0;
virtual bool GetCommand(unsigned int *Command = NULL) = 0;
};
#if defined REMOTE_KBD
@ -43,23 +42,27 @@ public:
cRcIoKBD(void);
virtual ~cRcIoKBD();
virtual void Flush(int WaitMs = 0);
virtual bool InputAvailable(bool Wait = false);
virtual bool GetCommand(unsigned int *Command, unsigned short *Address = NULL);
virtual bool InputAvailable(void);
virtual bool GetCommand(unsigned int *Command = NULL);
};
#elif defined REMOTE_RCU
class cRcIoRCU : public cRcIoBase {
class cRcIoRCU : public cRcIoBase, private cThread {
private:
cFile f;
int f;
unsigned char dp, code, mode;
unsigned short address;
unsigned short receivedAddress;
unsigned int receivedCommand;
bool receivedData, receivedRepeat;
int lastNumber;
bool SendCommand(unsigned char Cmd);
int ReceiveByte(bool Wait = true);
int ReceiveByte(int TimeoutMs = 0);
bool SendByteHandshake(unsigned char c);
bool SendByte(unsigned char c);
bool Digit(int n, int v);
virtual void Action(void);
public:
cRcIoRCU(char *DeviceName);
virtual ~cRcIoRCU();
@ -70,25 +73,24 @@ public:
virtual bool String(char *s);
virtual bool DetectCode(unsigned char *Code, unsigned short *Address);
virtual void Flush(int WaitMs = 0);
virtual bool InputAvailable(bool Wait = false);
virtual bool GetCommand(unsigned int *Command, unsigned short *Address = NULL);
virtual bool InputAvailable(void) { return receivedData; }
virtual bool GetCommand(unsigned int *Command = NULL);
};
#elif defined REMOTE_LIRC
class cRcIoLIRC : public cRcIoBase {
class cRcIoLIRC : public cRcIoBase, private cThread {
private:
enum { LIRC_KEY_BUF = 8, LIRC_BUFFER_SIZE = 128 };
cFile f;
int f;
char keyName[LIRC_KEY_BUF];
int repeat;
const char *ReceiveString(void);
bool receivedData, receivedRepeat;
virtual void Action(void);
public:
cRcIoLIRC(char *DeviceName);
virtual ~cRcIoLIRC();
virtual void Flush(int WaitMs = 0);
virtual bool InputAvailable(bool Wait = false);
virtual bool GetCommand(unsigned int *Command, unsigned short *Address = NULL);
virtual bool InputAvailable(void) { return receivedData; }
virtual bool GetCommand(unsigned int *Command = NULL);
};
#else

105
thread.c Normal file
View File

@ -0,0 +1,105 @@
/*
* thread.c: A simple thread base class
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: thread.c 1.1 2000/10/07 17:31:39 kls Exp $
*/
#include "thread.h"
#include <signal.h>
#include <unistd.h>
// --- cThread ---------------------------------------------------------------
// The signal handler is necessary to be able to use SIGIO to wake up any
// pending 'select()' call.
bool cThread::signalHandlerInstalled = false;
cThread::cThread(void)
{
if (!signalHandlerInstalled) {
signal(SIGIO, SignalHandler);
signalHandlerInstalled = true;
}
pthread_mutex_init(&mutex, NULL);
running = false;
parentPid = lockingPid = 0;
locked = 0;
}
cThread::~cThread()
{
pthread_mutex_destroy(&mutex);
}
void cThread::SignalHandler(int signum)
{
signal(signum, SignalHandler);
}
void *cThread::StartThread(cThread *Thread)
{
Thread->Action();
return NULL;
}
bool cThread::Start(void)
{
if (!running) {
running = true;
parentPid = getpid();
pthread_create(&thread, NULL, &StartThread, (void *)this);
}
return true; //XXX return value of pthread_create()???
}
void cThread::Stop(void)
{
pthread_exit(NULL);
}
bool cThread::Lock(void)
{
if (!lockingPid || lockingPid != getpid()) {
pthread_mutex_lock(&mutex);
lockingPid = getpid();
}
locked++;
return true;
}
void cThread::Unlock(void)
{
if (!--locked) {
lockingPid = 0;
pthread_mutex_unlock(&mutex);
}
}
void cThread::WakeUp(void)
{
kill(parentPid, SIGIO); // makes any waiting 'select()' call return immediately
}
// --- cThreadLock -----------------------------------------------------------
cThreadLock::cThreadLock(cThread *Thread)
{
thread = Thread;
locked = Thread->Lock();
}
cThreadLock::~cThreadLock()
{
if (locked)
thread->Unlock();
}
bool cThreadLock::Locked(void)
{
return locked;
}

57
thread.h Normal file
View File

@ -0,0 +1,57 @@
/*
* thread.h: A simple thread base class
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: thread.h 1.1 2000/10/08 08:36:21 kls Exp $
*/
#ifndef __THREAD_H
#define __THREAD_H
#include <pthread.h>
#include <sys/types.h>
class cThread {
friend class cThreadLock;
private:
pthread_t thread;
pthread_mutex_t mutex;
pid_t parentPid, lockingPid;
int locked;
bool running;
static bool signalHandlerInstalled;
static void SignalHandler(int signum);
static void *StartThread(cThread *Thread);
bool Lock(void);
void Unlock(void);
protected:
void WakeUp(void);
virtual void Action(void) = 0;
void Stop(void);
public:
cThread(void);
virtual ~cThread();
bool Start(void);
};
// cThreadLock can be used to easily set a lock in a thread and make absolutely
// sure that it will be unlocked when the block will be left. Several locks can
// be stacked, so a function that makes many calls to another function which uses
// cThreadLock may itself use a cThreadLock to make one longer lock instead of many
// short ones.
class cThreadLock {
private:
cThread *thread;
bool locked;
public:
cThreadLock(cThread *Thread);
~cThreadLock();
bool Locked(void);
};
#define LOCK_THREAD cThreadLock ThreadLock(this)
#endif //__THREAD_H

18
tools.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: tools.c 1.20 2000/09/29 16:19:28 kls Exp $
* $Id: tools.c 1.21 2000/10/07 18:02:24 kls Exp $
*/
#define _GNU_SOURCE
@ -393,6 +393,22 @@ bool cFile::AnyFileReady(int FileDes, int TimeoutMs)
return select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0 && (FileDes < 0 || FD_ISSET(FileDes, &set));
}
bool cFile::FileReady(int FileDes, int TimeoutMs)
{
#ifdef DEBUG_OSD
refresh();
#endif
fd_set set;
struct timeval timeout;
FD_ZERO(&set);
FD_SET(FileDes, &set);
if (TimeoutMs < 100)
TimeoutMs = 100;
timeout.tv_sec = 0;
timeout.tv_usec = TimeoutMs * 1000;
return select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0 && FD_ISSET(FileDes, &set);
}
// --- cListObject -----------------------------------------------------------
cListObject::cListObject(void)

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: tools.h 1.16 2000/09/29 16:19:31 kls Exp $
* $Id: tools.h 1.17 2000/10/07 18:00:21 kls Exp $
*/
#ifndef __TOOLS_H
@ -68,6 +68,7 @@ public:
int ReadString(char *Buffer, int Size);
bool Ready(bool Wait = true);
static bool AnyFileReady(int FileDes = -1, int TimeoutMs = 1000);
static bool FileReady(int FileDes, int TimeoutMs = 1000);
};
class cListObject {