What is the frequency of epoll_wait "wakeups"? - c

This question is elaboration and continuation of my previous question - On epoll_pwait, POSIX timers and X11 events. Most of X11 events is either delayed or dropped. I work with XCB window that displays some graphical information. The application has an insteractive input and had more or less static display. Now the requirenments had changed and I need to add some pereodic computations and have a interactive input.
The problem with the new requirenments is that computations goes at high rate. With that, I get inconsistent interaction with the XCB window. Input may lag behind, or change the rate of processing.
The setup is multiplex events with epoll_pwait. The events are signals, X11 events and recently added timers/timeout.
What I understand as of now, I need to separate user interaction from the computations. The problem with my setup, as of now, is that rate of X11 events changes in a way I can't explain.
So I decide to separate waiting on X11 events with the rest of the logic. Can you suggest a proper way to do it? Will having a X11 window in a separate thread/process/epoll set help?
And the actual question, as I look upon it now, is, what is a frequency of epoll_wait wakeups? I plan to have one epoll_wait in a loop. Maybe some processes to be wait on. I understand that epoll_wait will "wakeup" at some random points int time.
Update
My setup is close to this one:
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <math.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/signalfd.h>
#include <sys/epoll.h>
#include <sys/timerfd.h>
#include <sys/socket.h>
#include <xcb/xcb.h>
static struct timespec tm_p, tm_c, tm_diff;
static unsigned long nevents = 0;
static inline void timespec_diff(struct timespec *a, struct timespec *b, struct timespec *res) {
res->tv_sec = a->tv_sec - b->tv_sec;
res->tv_nsec = a->tv_nsec - b->tv_nsec;
if (res->tv_nsec < 0) {
--res->tv_sec;
res->tv_nsec += 1000000000L;
}
}
static double compute(){
double t = 1.0;
double eps = 1e-7;
double eps_2 = eps / 2.0;
clock_gettime(CLOCK_MONOTONIC, &tm_p);
while(t > eps){
t -= eps;
t += eps;
t -= eps_2 + eps_2;
}
clock_gettime(CLOCK_MONOTONIC, &tm_c);
timespec_diff(&tm_c, &tm_p, &tm_diff);
printf(" compute: %ld %f\n", tm_diff.tv_sec, tm_diff.tv_nsec / 1e9);
return (int)t;
}
/* defines for epoll */
#define MAXEVENTS 64
#define SET_EV(_ev,_fd,_events) _ev.data.fd = _fd; _ev.events = _events
static int xcb_get_atom(xcb_connection_t *c,
const char *name,
xcb_atom_t *atom)
{
xcb_intern_atom_cookie_t cookie;
xcb_generic_error_t *error;
xcb_intern_atom_reply_t *reply;
cookie = xcb_intern_atom(c, 0, strlen(name), name);
reply = xcb_intern_atom_reply(c, cookie, &error);
if(NULL == reply){
free(error);
return -1;
}
*atom = reply->atom;
free(reply);
return 0;
}
static int xcb_change_prop_wm_close(xcb_connection_t *c,
xcb_window_t window,
xcb_atom_t wm_p,
xcb_atom_t atom)
{
xcb_void_cookie_t cookie;
xcb_generic_error_t *error;
xcb_atom_enum_t type = XCB_ATOM_ATOM;
uint8_t format = 32;
uint32_t data_len = 1;
cookie = xcb_change_property_checked(c, /* xcb connection */
XCB_PROP_MODE_REPLACE, /* mode */
window, /* window */
wm_p, /* the property to change */
type, /* type of the property */
format, /* format(bits) */
data_len, /* number of elements(see format) */
&atom /* property data */
);
error = xcb_request_check(c, cookie);
if (error) {
free(error);
return -1;
}
return 0;
}
int main()
{
xcb_connection_t *c;
xcb_screen_t *screen;
xcb_window_t win;
xcb_atom_t a_wm_p;
xcb_atom_t wm_p_close;
struct epoll_event ep_ev, *ep_evs = NULL;
struct signalfd_siginfo siginf;
sigset_t mask_sigs, mask_osigs;
int sig_fd = -1, x11_fd = -1, ep_fd = -1, tm_fd = -1;
/* set up signals */
if(sigemptyset(&mask_sigs) < 0){
perror(" * sigemptyset(&mask_sigs)");
goto main_terminate;
}
if(sigaddset(&mask_sigs, SIGINT)){ /* these signals will be blocked. the signals will arrive */
perror(" * sigaddset(&mask_sigs, SIGINT)");
goto main_terminate;
}
if(sigaddset(&mask_sigs, SIGQUIT)){ /* to epoll and not to a default signal handler. */
perror(" * sigaddset(&mask_sigs, SIGQUIT)");
goto main_terminate;
}
/* save old sigmask, replace it with new sigmask */
if(sigprocmask(SIG_BLOCK, &mask_sigs, &mask_osigs) < 0){
perror(" * sigprocmask(SIG_BLOCK, &mask_sigs, &mask_osigs)");
goto main_terminate;
}
/* get signal file descriptor */
if((sig_fd = signalfd(-1, &mask_sigs, 0)) < 0){
perror(" * signalfd(-1, &mask_sigs, 0)");
goto main_terminate;
}
/* set signal fd as non-blocking */
{
int on = 1;
if(ioctl(sig_fd, FIONBIO, (char *)&on) < 0){
perror(" * ioctl(sig_fd, FIONBIO)");
goto main_terminate;
}
}
/* Open the connection to the X server */
c = xcb_connect (NULL, NULL);
/* Get the first screen */
screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
/* Ask for our window's Id */
win = xcb_generate_id(c);
/* Create the window */
{
unsigned int cw_mask = XCB_CW_BORDER_PIXEL
| XCB_CW_EVENT_MASK
;
/* values must follow in the incresing order of the cw_mask constants */
unsigned int cw_values[] = {screen->white_pixel,
XCB_EVENT_MASK_KEY_PRESS|XCB_EVENT_MASK_KEY_RELEASE
};
xcb_create_window (c, /* Connection */
XCB_COPY_FROM_PARENT, /* depth (same as root)*/
win, /* window Id */
screen->root, /* parent window */
0, 0, /* x, y */
150, 150, /* width, height */
10, /* border_width */
XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */
screen->root_visual, /* visual */
cw_mask, cw_values); /* masks */
}
/* get x11 connection file descriptor */
x11_fd = xcb_get_file_descriptor(c);
/* atom WM_PROTOCOLS */
if(xcb_get_atom(c, "WM_PROTOCOLS", &a_wm_p) < 0){
fprintf(stderr, " %s:%s:%d\n", __FILE__, __func__, __LINE__);
return -1;
}
/* atom window close */
if(xcb_get_atom(c, "WM_DELETE_WINDOW", &wm_p_close) < 0){
fprintf(stderr, " %s:%s:%d\n", __FILE__, __func__, __LINE__);
return -1;
}
{ /* wm prop: intercept close */
if(xcb_change_prop_wm_close(c, win, a_wm_p, wm_p_close) < 0){
fprintf(stderr, " %s:%s:%d\n", __FILE__, __func__, __LINE__);
goto main_terminate;
}
}
/* create epoll set file descriptor */
if((ep_fd = epoll_create(1)) < 0){
perror(" * epoll_create");
goto main_terminate;
}
/* allocate events for epoll queue */
if(NULL == (ep_evs = (struct epoll_event*)calloc(MAXEVENTS,sizeof(ep_ev)))){
perror(" * calloc(MAXEVENTS)");
goto main_terminate;
}
{ /* fd timer */
struct itimerspec ts;
if((tm_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK)) < 0){
perror(" * timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK)");
goto main_terminate;
}
ts.it_value.tv_sec = 1;
ts.it_value.tv_nsec = 0;
ts.it_interval.tv_sec = 0;
ts.it_interval.tv_nsec = (unsigned long)10e6; /* 10 msec */
if(timerfd_settime(tm_fd, 0, &ts, NULL) < 0){
perror(" * timerfd_settime(tm_fd, 0, &ts, NULL)");
goto main_terminate;
}
}
/* add X11 event */
SET_EV(ep_ev,x11_fd,EPOLLIN);
if(epoll_ctl (ep_fd, EPOLL_CTL_ADD, x11_fd, &ep_ev) < 0){
perror(" * epoll_ctl x11_fd");
goto main_terminate;
}
/* add timer event */
SET_EV(ep_ev,tm_fd,EPOLLIN);
if(epoll_ctl (ep_fd, EPOLL_CTL_ADD, tm_fd, &ep_ev) < 0){
perror(" * epoll_ctl tm_fd");
goto main_terminate;
}
/* add signal event */
SET_EV(ep_ev,sig_fd,EPOLLIN);
if(epoll_ctl (ep_fd, EPOLL_CTL_ADD, sig_fd, &ep_ev) < 0){
perror(" * epoll_ctl sig_fd");
goto main_terminate;
}
/* window title */
const char *title = "epoll_pwait";
xcb_change_property (c,
XCB_PROP_MODE_REPLACE,
win,
XCB_ATOM_WM_NAME,
XCB_ATOM_STRING,
8,
strlen (title),
title );
/* Map the window on the screen */
xcb_map_window (c, win);
/* Make sure commands are sent before we pause, so window is shown */
xcb_flush (c);
while(1){
int n, i, fd, status;
bool f_compute = false;
bool f_exit_sig = false;
bool f_win_close = false;
n = epoll_pwait (ep_fd, ep_evs, MAXEVENTS, -1, &mask_sigs); /* wait, signal safe */
if(n < 0){
fprintf(stderr, " * main(): %s:%s:%d\n", __FILE__, __func__, __LINE__);
status = 1;
goto main_terminate;
}
for(i = 0; i < n; ++i){ /* service epoll events */
fd = ep_evs[i].data.fd;
if(fd == sig_fd){ /* signal */
status = read(fd, &siginf, sizeof(siginf));
if(status != sizeof(siginf)){
fprintf(stderr,"read != sizeof(siginf)");
goto main_terminate;
}
if(siginf.ssi_signo == SIGINT){
printf("got SIGINT\n");
f_exit_sig = true;
}else if(siginf.ssi_signo == SIGQUIT){
printf("got SIGQUIT\n");
f_exit_sig = true;
goto main_terminate;
}else {
printf("got unregistered signal\n");
}
}else if(fd == x11_fd){ /* x11 event */
xcb_generic_event_t *event;
while((event = xcb_poll_for_event(c))){
if (event && (event->response_type == 0)){ /* error recieved */
free(event);
goto main_terminate;
}
switch(event->response_type & ~0x80){
case XCB_CLIENT_MESSAGE: { /* window close */
xcb_client_message_event_t *ce = (xcb_client_message_event_t*)event;
if(ce->data.data32[0] == wm_p_close){ /* window should close */
f_win_close = true;
}
} break;
case XCB_KEY_PRESS: { /* keyboard key press */
printf("XCB_KEY_PRESS\n");
nevents++;
} break;
} /* end switch */
free(event);
} /* end while event loop */
}else if(fd == tm_fd){ /* timer event */
uint64_t overrun;
status = read(fd, &overrun, sizeof(uint64_t));
if(status != EAGAIN) {
//~ printf(" ! timer overruns: %lu\n", overrun);
}
f_compute = true;
}
} /* finish service epoll events */
if(f_exit_sig){ /* exit signal */
goto main_terminate;
}
if(f_win_close){ /* window close */
goto main_terminate;
}
if(f_compute){ /* do some computations */
compute();
xcb_flush(c);
}
} /* end while(1) */
main_terminate:
if(sig_fd != -1){
close(sig_fd);
}
if(tm_fd != -1){
close(tm_fd);
}
if(ep_fd != -1){
close(ep_fd);
}
if(ep_evs){
free(ep_evs);
}
xcb_disconnect(c);
if (sigprocmask(SIG_SETMASK, &mask_osigs, NULL) < 0){
perror(" * sigprocmask(SIG_SETMASK, &mask_osigs, NULL)");
}
printf("received %lu events\n", nevents);
return 0;
}
With the above, I can not reproduce input lag I do have in more verbose program. I test the above with xdotool, send some input X11 events, and my eye can't catch any visible input delay. All events get delivered. For now I can not post a full code that I have problem with.

what is a frequency of epoll_wait wakeups?
I'll assume you are talking about the precision of wakeups. This surely depends on kernel details, but let's just make an experiment: We can write a small program that tests how long epoll_wait takes. This will test both a timeout of zero and a timeout of 1 ms since a timeout of zero might be treated specially.
Output on my system:
empty: avg 0.015636 μs, min 0.014 μs, max 0.065 μs
sleep 1 ms: avg 1108.55 μs, min 1014.72 μs, max 1577.42 μs
epoll_wait 0: avg 0.761084 μs, min 0.38 μs, max 37.787 μs
epoll_wait 1: avg 1108.97 μs, min 1017.22 μs, max 2602.4 μs
Doing nothing (empty) measures less than a microsecond, so the following results should be somewhat reliable. The minimum time is also not zero, so the clock has enough precision for what we are doing.
Sleeping 1 ms sleeps at least 1.014 ms, but there also was a case of 1.5 ms. I guess that means that wakeups are not all that precise.
Using epoll_wait() to do nothing take less than a microsecond. More than doing nothing, but this still does basically nothing, so perhaps this really just measures the syscall overhead...?
Sleeping 1 ms with epoll_wait() behaves more or less the same as sleeping for 1 ms with nanosleep().
If you want to improve this experiment, you could actually register some FDs via epoll_ctl(). It might be that the kernel handles "empty" epoll FDs specially.
#include <stdio.h>
#include <sys/epoll.h>
#include <time.h>
#include <unistd.h>
#define MEASUREMENT_COUNT 10000
#define NUM_EVENTS 42
static int epoll_fd;
double diff_micro_sec(struct timespec *a, struct timespec *b) {
double sec = a->tv_sec - b->tv_sec;
double ns = a->tv_nsec - b->tv_nsec;
return sec * 1e6 + ns / 1e3;
}
static void empty(void) {
}
static void sleep_one_ms(void) {
struct timespec spec;
spec.tv_sec = 0;
spec.tv_nsec = 1000 * 1000;
nanosleep(&spec, NULL);
}
static void epoll_wait_0(void) {
struct epoll_event events[NUM_EVENTS];
epoll_wait(epoll_fd, events, NUM_EVENTS, 0);
}
static void epoll_wait_1(void) {
struct epoll_event events[NUM_EVENTS];
epoll_wait(epoll_fd, events, NUM_EVENTS, 1);
}
static void do_it(const char *name, void (*func)(void)) {
double sum, min, max;
struct timespec a, b;
for (int i = 0; i < MEASUREMENT_COUNT; i++) {
double diff;
clock_gettime(CLOCK_MONOTONIC, &a);
func();
clock_gettime(CLOCK_MONOTONIC, &b);
diff = diff_micro_sec(&b, &a);
if (i == 0) {
sum = diff;
min = diff;
max = diff;
} else {
sum += diff;
if (diff < min)
min = diff;
if (diff > max)
max = diff;
}
}
printf("%14s: avg %g μs, min %g μs, max %g μs\n", name, sum / MEASUREMENT_COUNT, min, max);
}
int main() {
do_it("empty", empty);
do_it("sleep 1 ms", sleep_one_ms);
epoll_fd = epoll_create(1);
do_it("epoll_wait 0", epoll_wait_0);
do_it("epoll_wait 1", epoll_wait_1);
close(epoll_fd);
return 0;
}

Related

Increasing robustness of executing a function every x seconds

I have written some code that tries to call a function (called worker) every x seconds (in this example, I chose 1s as the interval time). The code is a minimal working example that in reality is way more complex than this.
The code works when it is this simple, but I stumble across errors when running the more complex version for a longer period of time. Thus, I want to increase the robustness of this code an would like to get some ideas on how to do that.
Basically, the worker gets some data, processes it an writes it to a file. I open the file during every call to the worker. In the tests, after some time I get an error that the file cannot be opened anymore. In this regard I also noticed that this happens (maybe just by chance) everytime the worker execution time exceeds the interval time. Reason for this is the getter function which pulls data from remote and this can take some time, depending on the network traffic.
I've been thinking of trying a multithreaded approach, but I am not sure if this is worth the hassle. I would be grateful for any pointers on how to do this in a more robust way.
#include <unistd.h>
#include <stdbool.h>
#include <stdio.h>
#include <signal.h>
#include <stdint.h>
#include <time.h>
#define ALARM_INTERVAL_SEC 1
#define ALARM_INTERVAL_USEC 0
static bool running = true;
static struct itimerval alarm_interval;
static struct timeval previous_time;
static uint64_t loop_count = 0;
static FILE* testfile;
static void
signal_handler(int signum)
{
if (signum == SIGINT || signum == SIGTERM)
{
running = false;
}
}
static void
worker(int signum)
{
// Reset the alarm interval
if(setitimer(ITIMER_REAL, &alarm_interval, NULL) < 0)
{
perror("Error: setitimer");
raise(SIGTERM);
return;
}
struct timeval current_time;
gettimeofday(&current_time, NULL);
printf("Loop count: %lu\n", loop_count);
printf("Loop time: %f us\n\n", (current_time.tv_sec - previous_time.tv_sec) * 1e6 +
(current_time.tv_usec - previous_time.tv_usec));
previous_time = current_time;
// convert time to human-readable format
char tmbuf[64];
char buf[64];
time_t nowtime = current_time.tv_sec;
struct tm *nowtm = localtime(&nowtime);
strftime(tmbuf, sizeof(tmbuf), "%Y-%m-%d %H:%M:%S", nowtm);
snprintf(buf, sizeof(buf), "%s.%06ld", tmbuf, current_time.tv_usec);
sleep(0.5);
// DO STH
testfile = fopen("testfile.txt", "ab+");
if(testfile == NULL)
{
printf("Error: open testfile");
raise(SIGTERM);
return;
}
fprintf(testfile, "[%s] Loop count: %lu\n", buf, loop_count);
fclose(testfile);
loop_count++;
}
int
main(int argc, char* argv[])
{
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
signal(SIGALRM, worker);
// Set the alarm interval
alarm_interval.it_interval.tv_sec = 0;
alarm_interval.it_interval.tv_usec = 0;
alarm_interval.it_value.tv_sec = ALARM_INTERVAL_SEC;
alarm_interval.it_value.tv_usec = ALARM_INTERVAL_USEC;
if(setitimer(ITIMER_REAL, &alarm_interval, NULL) < 0)
{
perror("Error: setitimer");
return -1;
}
gettimeofday(&previous_time, NULL);
while(running)
{
sleep(1);
}
alarm_interval.it_value.tv_sec = 0;
alarm_interval.it_value.tv_usec = 0;
if(setitimer(ITIMER_REAL, &alarm_interval, NULL) < 0)
{
perror("Error: resetting itimer failed");
return -1;
}
return 0;
}

how to code the kernel mode of rt-linux?

Interrupts are handled in the kernel mode but to handle interrupt in rt linux they are saying that :
I need to write code using RTLinux in kernel space and with kernel modules. With QNX, you can't write kernel modules (the kernel is not open) and you have real-time in user-space.
my question :
How to write a code in kernel space ??
what is exactly mean by that ??
where should i modify the kernel ??
someone Please suggest some ideas.
udp code :
int CreateSocket()
{
socklen_t len;
// Socket creation for UDP
acceptSocket=socket(AF_INET,SOCK_DGRAM,0);
if(acceptSocket==-1)
{
printf("Failure: socket creation is failed, failure code\n");
return 1;
}
else
{
printf("Socket started!\n");
}
memset(&addr, 0, sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_port=htons(port);
addr.sin_addr.s_addr=htonl(INADDR_ANY);
rc=bind(acceptSocket,(struct sockaddr*)&addr,sizeof(addr));
if(rc== -1)
{
printf("Oh dear, something went wrong with bind()! %s\n", strerror(errno));
return 1;
}
else
{
printf("Socket an port %d \n",port);
}
while(rc!=-1)
{
len = sizeof(client);
rc=recvfrom(acceptSocket,buf, 256, 0, (struct sockaddr*) &client, &len);
//I am calculating the time here
InterruptTime = GetTimeStamp();
measurements[17] = InterruptTime;
if(rc==0)
{
printf("Server has no connection..\n");
break;
}
if(rc==-1)
{
printf("Oh dear, something went wrong with read()! %s\n", strerror(errno));
break;
}
XcpIp_RxCallback( (uint16) rc, (uint8*) buf, (uint16) port );
}
close(acceptSocket);
return 1;
}
int main()
{
CreateSocket();
while(1)
{
TASK1(Task2ms_Raster);
TASK2(Task10ms_Raster);
TASK3(Task100ms_Raster);
}
Unlike QNX the Linux kernel is open source software. Which means that you can modify and change it in whatever ways you desire. You grab the sources from http://kernel.org (preferrably you use Git to clone into a local repository), make your modifications, additions, etc. compile the think and boot your computer with it.
Note that Linux since version 2.6 also offers realtime scheduling, which might be sufficient.
Update code example
For the time raster task execution I suggest the following:
#define _POSIX_C_SOURCE 200809L
#define _XOPEN_SOURCE 500
#include <sched.h> /* for sched_setsched */
#include <unistd.h> /* for usleep */
#include <time.h> /* for clock_gettime */
#include <string.h> /* for memset */
#define MS_to_US(x) ((x)*1000)
useconds_t delta_t_us(struct timespec const *a, struct timespec const *b)
{
time_t const delta_sec = b->tv_sec - a->tv_sec;
long const delta_nsec = b->tv_nsec - a->tv_nsec;
/* this might actually overflow for "long" time intervalls"
* should be safe for a delta_t < 2ms though */
return delta_sec * 1000000 + delta_nsec / 1000;
}
void rastertask()
{
struct sched_param sparm;
memset(&sparm, 0, sizeof(sparm));
sparm.sched_priority = 10; /* 0 = lowest, 99 = highest */
sched_setscheduler(
0 /* pid, 0 ==> this process */,
SCHED_RR /* policy */,
&sparm);
unsigned int n_loop;
for(n_loop=0;;n_loop++) {
struct timespec ts_start, ts_end;
clock_gettime(CLOCK_MONOTONIC, &ts_start);
TASK1(); /* gets called every 2ms */
if( (n_loop % 5) == 0) {
TASK2(); /* get called every 5 * 2ms = 10ms */
}
if( (n_loop % 50) == 0) {
TASK2(); /* get called every 50 * 2ms = 100ms */
}
if( (n_loop % 250) == 0 ) {
/* reset loop counter when smallest common
* multiple of timing grid has been reached */
n_loop = 0;
}
clock_gettime(CLOCK_MONOTONIC, &ts_end);
useconds_t const tasks_execution_time = delta_t_us(&ts_start, &ts_end);
if( tasks_execution_time >= MS_to_US(2) ) {
/* report an error that tasks took longer than 2ms to execute */
}
/* wait for 2ms - task_execution_time so that tasks get called in
* a close 2ms timing grid */
usleep( MS_to_US(2) - tasks_execution_time );
}
}
Please note that the process requires either CAP_SYS_NICE privileges (prior to Linux 2.6.12) or sufficient RLIMIT_RTPRIO resource limits to be able to set its priority.

Errors in using my self-built library

I am now using pocketSphinx to build a C library. The problem is that if i put the main function together with all the header files(as the code below), it works well. Then i made a static library(with code not including the main function). But when i tried to use this lib in another main function, errors happened as:
/usr/local/include/sphinxbase/ad.h:106:27: FATAL error: sphinx_config.h:no such file or directory
... when compiling. I think this might be a problem related to the path of my header files.
Can any one tell me how to solve this?
The code below works well:
//system headerfiles
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/time.h>
#include <signal.h>
#include <setjmp.h>
//generic live audio interface for recording and playback
#include <sphinxbase/ad.h>
#include <sphinxbase/cont_ad.h>
//pocketsphinx headerfiles
#include <sphinxbase/err.h>
#include "pocketsphinx.h"
static ps_decoder_t *ps;
static cmd_ln_t *config;
static void print_word_times(int32 start)
{
ps_seg_t *iter = ps_seg_iter(ps, NULL);
while (iter != NULL)
{
int32 sf, ef, pprob;
float conf;
ps_seg_frames (iter, &sf, &ef);
pprob = ps_seg_prob (iter, NULL, NULL, NULL);
conf = logmath_exp(ps_get_logmath(ps), pprob);
printf ("%s %f %f %f\n", ps_seg_word (iter), (sf + start) / 100.0, (ef + start) / 100.0, conf);
iter = ps_seg_next (iter);
}
}
/* Sleep for specified msec */
static void sleep_msec(int32 ms)
{
struct timeval tmo;
tmo.tv_sec = 0;
tmo.tv_usec = ms * 1000; //original was 1000 try to modify here to reduce the sleeping time
select(0, NULL, NULL, NULL, &tmo);
}
char const *recognize_from_microphone()
{
ad_rec_t *ad;
int16 adbuf[4096];
int32 k, ts, rem;
char const *hyp;
char const *uttid;
cont_ad_t *cont;
char word[256];
if ((ad = ad_open_dev(cmd_ln_str_r(config, "-adcdev"),
(int)cmd_ln_float32_r(config, "-samprate"))) == NULL)
E_FATAL("Failed top open audio device\n");
/* Initialize continuous listening module */
if ((cont = cont_ad_init(ad, ad_read)) == NULL)
E_FATAL("Failed to initialize voice activity detection\n");
if (ad_start_rec(ad) < 0)
E_FATAL("Failed to start recording\n");
if (cont_ad_calib(cont) < 0)
E_FATAL("Failed to calibrate voice activity detection\n");
/* Indicate listening for next utterance */
printf("READY....\n");
fflush(stdout);
fflush(stderr);
/* Wait data for next utterance */
while ((k = cont_ad_read(cont, adbuf, 4096)) == 0)
sleep_msec(100);
if (k < 0)
E_FATAL("Failed to read audio\n");
/*
* Non-zero amount of data received; start recognition of new utterance.
* NULL argument to uttproc_begin_utt => automatic generation of utterance-id.
*/
if (ps_start_utt(ps, NULL) < 0)
E_FATAL("Failed to start utterance\n");
ps_process_raw(ps, adbuf, k, FALSE, FALSE);
printf("Listening...\n");
fflush(stdout);
/* Note timestamp for this first block of data */
ts = cont->read_ts;
/* Decode utterance until end (marked by a "long" silence, >1sec) */
for (;;) {
/* Read non-silence audio data, if any, from continuous listening module */
if ((k = cont_ad_read(cont, adbuf, 4096)) < 0)
E_FATAL("Failed to read audio\n");
if (k == 0) {
/*
* No speech data available; check current timestamp with most recent
* speech to see if more than 1 sec elapsed. If so, end of utterance.
*/
if ((cont->read_ts - ts) > DEFAULT_SAMPLES_PER_SEC)
break;
}
else {
/* New speech data received; note current timestamp */
ts = cont->read_ts;
}
/*
* Decode whatever data was read above.
*/
rem = ps_process_raw(ps, adbuf, k, FALSE, FALSE);
/* If no work to be done, sleep a bit */
if ((rem == 0) && (k == 0))
sleep_msec(20);
}
/*
* Utterance ended; flush any accumulated, unprocessed A/D data and stop
* listening until current utterance completely decoded
*/
ad_stop_rec(ad);
while (ad_read(ad, adbuf, 4096) >= 0);
cont_ad_reset(cont);
printf("Stopped listening, please wait...\n");
fflush(stdout);
/* Finish decoding, obtain and print result */
ps_end_utt(ps);
hyp = ps_get_hyp(ps, NULL, &uttid);
printf("%s: %s\n", uttid, hyp);
fflush(stdout);
/* Resume A/D recording for next utterance */
if (ad_start_rec(ad) < 0)
E_FATAL("Failed to start recording\n");
cont_ad_close(cont);
ad_close(ad);
return hyp;
}
static jmp_buf jbuf;
static void sighandler(int signo)
{
longjmp(jbuf, 1);
}
int main(int argc, char *argv[])
{
char const *word;
config = cmd_ln_init(NULL, ps_args(), TRUE,
"-hmm", MODELDIR "/hmm/en_US/hub4wsj_sc_8k",
"-lm", "/home/nieluming/Desktop/speech_lib/models/2253.lm",
"-dict", "/home/nieluming/Desktop/speech_lib/models/2253.dic",
NULL);
if (config == NULL)
return 1;
ps = ps_init(config);
if (ps == NULL)
return 1;
signal(SIGINT, &sighandler);
if (setjmp(jbuf) == 0)
word = recognize_from_microphone();
printf("%s\n", word);
ps_free(ps);
return 0;
}
As i have stated, when i made a lib with code above and a headfile as below:
#ifndef MIC_RECOG_H
#define MIC_RECOG_H
char const *recognize_from_microphone();
#endif
"no header file problems" will happen when using this lib.
Add -I/usr/local/include/sphinxbase to the set of compiler options in use.
-I <path> adds path to the set of pathes being searched for files to be included.

Consumer - Producer, assertion failure

I have the bounded buffer, producer consumer problem to deal with and can only modify the prod and cons functions. This code runs without issues with only one consumer and producer threads. But with multiple of each it always gives me the same problem, sooner or later:
p5p1: p5p2a.c:207: bb_remove: Assertion `bbp->cnt > 0' failed.
What I don't get is how can this error occur when I check the bbp->cnt variable before calling the bbp_remove() function.
EDIT: The problem has been solved. I was not checking the variable within the lock, in either of the functions.
#include <sys/times.h>
#include <unistd.h>
#include <assert.h>
#include <stdlib.h>
#include <pthread.h>
#include <time.h>
#include <errno.h>
#include <stdio.h>
#define DEBUG 0
#define BUF_SIZE 100000
#define ITER 10000000
#define PROD_THRD 3
#define CONS_THRD 3
#define USAGE_STRING "Usage: %s\n"
extern int errno;
/* This is the bounded buffer type */
typedef struct {
int cnt, in, out;
pthread_mutex_t lock; /* Mutex to avoid race conditions */
int buf[BUF_SIZE]; /* The data passed is the id of the
* producer */
} bbuf_t;
typedef struct {
bbuf_t *bbp;
int id;
} parg_t;
/*
* yield()
* Because there is no yield system call in Linux, what we
* do is to put the thread to sleep for 1 ms. Actually, it
* will sleep for at least 1/HZ, which is 10 ms in Linux/386.
*/
#define YIELD_s 0
#define YIELD_ns 1000000
void yield() {
struct timespec st = {YIELD_s, YIELD_ns};
if( (nanosleep(&st, NULL)) == -1 && (errno == EINVAL)) {
perror("nanosleep");
pthread_exit(NULL);
}
}
/* Initialize bounded buffer */
int bbuf_init(bbuf_t *bbp) {
if(bbp == NULL)
return 0;
bbp->in = 0;
bbp->out = 0;
bbp->cnt = 0;
pthread_mutex_init(&(bbp->lock), NULL); /* I do not understand, but the
* compiler complains when I use
* PTHREAD_MUTEX_INITIALIZER */
return 1;
}
/* Print the bounded buffer members that matter */
void print_bbuf(bbuf_t *bbp) {
printf("bbp->in = %d bbp->out = %d bbp_cnt = %d \n",
bbp->in, bbp->out, bbp->cnt);
}
/* To validate the value of the members in, out and cnt of bbuf_t */
int val(int n, int min, int max) {
return( (min <= n) && (n <= max));
}
/* Ensure that the values of the members in, out and cnt are consistent */
int consist(int cnt, int in, int out) {
return ( in == ((out + cnt) % BUF_SIZE) );
}
/* This is the code of the checker thread. It is used to ensure that
* the bounded buffer has not been corrupted.
* Every 100 ms it checks the values of: in, out and cnt.
* This thread exits either if it detects the buffer has been corrupted
* or if it does not detect any activity in 50 consecutive iterations,
* i.e. approximately 5s. */
/* These constants are used with nanosleep() and
* put a process to sleep for 100 ms */
#define SLEEP_s 0
#define SLEEP_ns 100000000
#define MAX_IDLE 50
void *check(void *arg) {
bbuf_t *bbp = arg;
int cnt[2], in[2], out[2]; /* values read */
int idle;
struct timespec st = {SLEEP_s, SLEEP_ns}; /* 100 ms */
while(1) {
pthread_mutex_lock( &(bbp->lock) );
in[1] = bbp->in;
out[1] = bbp->out;
cnt[1] = bbp->cnt;
pthread_mutex_unlock( &(bbp->lock) );
if(in[1] == in[0] && out[1] == out[0] && cnt[1] == cnt[0] ) {
idle++;
if( idle >= MAX_IDLE ) {
printf("Checking thread exiting:");
print_bbuf(bbp);
printf("\t no activity detected for some time.\n");
pthread_exit(NULL);
}
} else {
idle = 0;
}
if( !val(in[1], 0, BUF_SIZE - 1) ) {
printf("Invalid value in = %d \n", in[1]);
pthread_exit(NULL);
} else if ( !val(out[1], 0, BUF_SIZE - 1) ) {
printf("Invalid value out = %d \n", out[1]);
pthread_exit(NULL);
} else if ( !val(cnt[1], 0, BUF_SIZE) ) {
printf("Invalid value cnt = %d \n", cnt[1]);
pthread_exit(NULL);
} else if ( !consist(cnt[1], in[1], out[1]) ) {
printf("Inconsistent buffer: cnt = %d in = %d out = %d \n",
cnt[1], in[1], out[1]);
pthread_exit(NULL);
}
if( (nanosleep(&st, NULL) == -1) && (errno == EINVAL)) {
perror("nanosleep");
pthread_exit(NULL);
}
in[0] = in[1];
out[0] = out[1];
cnt[0] = cnt[1];
}
}
/* The producer threads may use this code to
* enter one item into the buffer */
void bb_enter(bbuf_t *bbp, int me) {
assert( bbp->cnt < BUF_SIZE);
(bbp->buf)[bbp->in] = me;
(bbp->in)++;
(bbp->in) %= BUF_SIZE;
(bbp->cnt)++;
//printf("%d\n",bbp->cnt);
}
/* This is the code for the producer threads.
*
* To avoid busy waiting (or at least too much busy waiting) the producers
* should yield, using the yield() defined above, if the buffer is
* full. In that case, they should print a debugging message as well.
*
* Each producer should produce ITER (10 M) items: an integer with
* the id it receives in prod()'s argument.
*/
void *prod(void *arg) {
parg_t *parg = (parg_t *)arg;
bbuf_t *bbp = parg->bbp;
int me = parg->id;
/* Add variables and code, if necessary */
printf("I am a producer and have started\n");
int gcnt = 0;
while( gcnt <= ITER ){
if(bbp->cnt < BUF_SIZE){
pthread_mutex_lock(&(bbp->lock));
bb_enter(bbp,me);
gcnt++;
pthread_mutex_unlock(&(bbp->lock));}
else if( bbp->cnt == (BUF_SIZE-1)) {printf("I shall produce yield()\n"); yield();}
}
printf("I am a producer and have ended\n");
return;
}
/* The consumer threads may use this function to
* remove an item */
int bb_remove(bbuf_t *bbp) {
int val;
assert(bbp->cnt > 0);
val = (bbp->buf)[bbp->out];
(bbp->out)++;
(bbp->out) %= BUF_SIZE;
(bbp->cnt)--;
return val;
}
/* This is the code for the consumer threads.
* To avoid busy waiting (or at least too much busy waiting) consumers
* should yield, using the yield() defined above, if the buffer is
* empty. In that case, they should print a debugging message as well.
*
* Each consumer should consume ITER (10 M) items, and keep track of the
* producers of the items it consumes: use the cnt[] below.
*/
void *cons(void *arg) {
bbuf_t *bbp = (bbuf_t *)arg;
int cnt[PROD_THRD];
/* Add variables and code, if necessary:
* do not forget to initialize cnt */
printf("I am a consumer and have started\n");
int i;
for(i = 0; i < PROD_THRD; i++){
cnt[i] = 0;}
int temp;
int gcnt = 0;
while( gcnt <= ITER ){
if(bbp->cnt > 0){
pthread_mutex_lock(&(bbp->lock));
temp = bb_remove(bbp);
gcnt++;
cnt[temp]++;
pthread_mutex_unlock(&(bbp->lock));}
else if( bbp->cnt == 0) {printf("I shall consume yield()\n"); yield();}
}
printf("I am a consumer and have ended\n");
return;
}
int main(int argc, char *argv[]) {
int i;
pthread_t *tid, ctid;
parg_t *parg;
bbuf_t *bbp;
/* This is to measure the time it takes to run the program */
struct tms t;
clock_t start, end;
long ticks = sysconf(_SC_CLK_TCK);
start = times(&t);
if( argc != 1 ) {
printf(USAGE_STRING, argv[0]);
exit(1);
}
/* Array for pthread_join() */
if((tid = (pthread_t *) malloc((PROD_THRD + CONS_THRD) * sizeof(pthread_t)))
== NULL ) {
printf("Out of memory.\n");
exit(2);
}
/* Allocate Bounded Buffer */
if((bbp = (bbuf_t *) malloc(sizeof(bbuf_t))) == NULL ) {
printf("Out of memory. \n");
exit(2);
}
/* Initialize Bounded Buffer */
if( bbuf_init(bbp) == 0 ) {
printf("Failed to initialize bounded buffer\n");
exit(3);
}
/* Arguments for producer threads */
if((parg = (parg_t *) malloc( PROD_THRD * sizeof (parg_t))) == NULL ) {
printf("Out of memory.\n");
exit(2);
}
/* Create checker thread */
if( pthread_create(&ctid, NULL, check, bbp) )
perror("pthread_create");
printf("Created checker thread %u\n", (unsigned)ctid);
/* Create consumer threads */
for( i = 0; i < CONS_THRD; i++ ) {
/* We pass the same data structure, the bounded buffer,
* to each consumer: they need to synchronize to access it */
if( pthread_create(tid+i, NULL, cons, bbp) )
perror("pthread_create");
printf("Created consumer thread %u\n", (unsigned)tid[i]);
}
/* Create producer threads */
for( i = 0; i < PROD_THRD; i++ ) {
/* Because we want each consumer to keep track of the
* producer of the items it consumes, we assign an
* id to each producer thread */
parg[i].bbp = bbp;
parg[i].id = i;
if( pthread_create(tid+(i+CONS_THRD), NULL, prod, parg+i) )
perror("pthread_create");
printf("Created producer thread %u (%d)\n", (unsigned)tid[i+CONS_THRD], i);
}
/* Join consumer and producer threads */
for( i = 0; i < CONS_THRD + PROD_THRD; i ++ ) {
if( pthread_join(tid[i], NULL) == 0 ) {
printf("Joined thread %u.\n", (unsigned)tid[i]);
} else {
printf("Failed to join thread %u\n", (unsigned)tid[i]);
}
}
/* Join checker thread */
if( pthread_join(ctid, NULL) == 0 ) {
printf("Joined checker thread %u.\n", (unsigned)ctid);
} else {
printf("Failed to join checker thread %u\n", (unsigned)ctid);
}
/* How long did it take to run this ? */
end = times(&t);
printf("Wall time %2.4f s \n", (float)(end - start) / ticks);
return 0;
}
You should enter the mutex lock before you check bbp->cnt. Since you are checking it before you enter the mutex, another thread can reduce the value before you acquire the mutex and try to reduce the value yourself.

How do you make a precise countdown timer using clock_gettime?

Could somebody please explain how to make a countdown timer using clock_gettime, under Linux. I know you can use the clock() function to get cpu time, and multiply it by CLOCKS_PER_SEC to get actual time, but I'm told the clock() function is not well suited for this.
So far I have attempted this (a billion is to pause for one second)
#include <stdio.h>
#include <time.h>
#define BILLION 1000000000
int main()
{
struct timespec rawtime;
clock_gettime(CLOCK_MONOTONIC_RAW, &rawtime);
unsigned long int current = ( rawtime.tv_sec + rawtime.tv_nsec );
unsigned long int end = (( rawtime.tv_sec + rawtime.tv_nsec ) + BILLION );
while ( current < end )
{
clock_gettime(CLOCK_MONOTONIC_RAW, &rawtime);
current = ( rawtime.tv_sec + rawtime.tv_nsec );
}
return 0;
}
I know this wouldn't be very useful on its own, but once I've found out how to time correctly I can use this in my projects. I know that sleep() can be used for this purpose, but I want to code the timer myself so that I can better integrate it in my projects - such as the possibility of it returning the time left, as opposed to pausing the whole program.
Please, do not do that. You're burning CPU power for nothing in a busy loop.
Why not use the nanosleep() function instead? It's perfectly suited to the use case you outlined. Or, if you want an easier interface, perhaps something like
#define _POSIX_C_SOURCE 200809L
#include <time.h>
#include <errno.h>
/* Sleep for the specified number of seconds,
* and return the time left over.
*/
double dsleep(const double seconds)
{
struct timespec req, rem;
/* No sleep? */
if (seconds <= 0.0)
return 0.0;
/* Convert to seconds and nanoseconds. */
req.tv_sec = (time_t)seconds;
req.tv_nsec = (long)((seconds - (double)req.tv_sec) * 1000000000.0);
/* Take care of any rounding errors. */
if (req.tv_nsec < 0L)
req.tv_nsec = 0L;
else
if (req.tv_nsec > 999999999L)
req.tv_nsec = 999999999L;
/* Do the nanosleep. */
if (nanosleep(&req, &rem) != -1)
return 0.0;
/* Error? */
if (errno != EINTR)
return 0.0;
/* Return remainder. */
return (double)rem.tv_sec + (double)rem.tv_nsec / 1000000000.0;
}
The difference is that using this one the CPU is free to do something else, rather than spin like a crazed squirrel on speed.
This is not an answer, but an example of how to use signals and a POSIX timer to implement a timeout timer; intended as a response to the OP's followup question in a comment to the accepted answer.
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
/* Timeout timer.
*/
static timer_t timeout_timer;
static volatile sig_atomic_t timeout_state = 0;
static volatile sig_atomic_t timeout_armed = 2;
static const int timeout_signo = SIGALRM;
#define TIMEDOUT() (timeout_state != 0)
/* Timeout signal handler.
*/
static void timeout_handler(int signo, siginfo_t *info, void *context __attribute__((unused)))
{
if (timeout_armed == 1)
if (signo == timeout_signo && info && info->si_code == SI_TIMER)
timeout_state = ~0;
}
/* Unset timeout.
* Returns nonzero if timeout had expired, zero otherwise.
*/
static int timeout_unset(void)
{
struct itimerspec t;
const int retval = timeout_state;
/* Not armed? */
if (timeout_armed != 1)
return retval;
/* Disarm. */
t.it_value.tv_sec = 0;
t.it_value.tv_nsec = 0;
t.it_interval.tv_sec = 0;
t.it_interval.tv_nsec = 0;
timer_settime(timeout_timer, 0, &t, NULL);
return retval;
}
/* Set timeout (in wall clock seconds).
* Cancels any pending timeouts.
*/
static int timeout_set(const double seconds)
{
struct itimerspec t;
/* Uninitialized yet? */
if (timeout_armed == 2) {
struct sigaction act;
struct sigevent evt;
/* Use timeout_handler() for timeout_signo signal. */
sigemptyset(&act.sa_mask);
act.sa_sigaction = timeout_handler;
act.sa_flags = SA_SIGINFO;
if (sigaction(timeout_signo, &act, NULL) == -1)
return errno;
/* Create a monotonic timer, delivering timeout_signo signal. */
evt.sigev_value.sival_ptr = NULL;
evt.sigev_signo = timeout_signo;
evt.sigev_notify = SIGEV_SIGNAL;
if (timer_create(CLOCK_MONOTONIC, &evt, &timeout_timer) == -1)
return errno;
/* Timeout is initialzied but unarmed. */
timeout_armed = 0;
}
/* Disarm timer, if armed. */
if (timeout_armed == 1) {
/* Set zero timeout, disarming the timer. */
t.it_value.tv_sec = 0;
t.it_value.tv_nsec = 0;
t.it_interval.tv_sec = 0;
t.it_interval.tv_nsec = 0;
if (timer_settime(timeout_timer, 0, &t, NULL) == -1)
return errno;
timeout_armed = 0;
}
/* Clear timeout state. It should be safe (no pending signals). */
timeout_state = 0;
/* Invalid timeout? */
if (seconds <= 0.0)
return errno = EINVAL;
/* Set new timeout. Check for underflow/overflow. */
t.it_value.tv_sec = (time_t)seconds;
t.it_value.tv_nsec = (long)((seconds - (double)t.it_value.tv_sec) * 1000000000.0);
if (t.it_value.tv_nsec < 0L)
t.it_value.tv_nsec = 0L;
else
if (t.it_value.tv_nsec > 999999999L)
t.it_value.tv_nsec = 999999999L;
/* Set it repeat once every millisecond, just in case the initial
* interrupt is missed. */
t.it_interval.tv_sec = 0;
t.it_interval.tv_nsec = 1000000L;
if (timer_settime(timeout_timer, 0, &t, NULL) == -1)
return errno;
timeout_armed = 1;
return 0;
}
int main(void)
{
char *line = NULL;
size_t size = 0;
ssize_t len;
fprintf(stderr, "Please supply input. The program will exit automatically if\n");
fprintf(stderr, "it takes more than five seconds for the next line to arrive.\n");
fflush(stderr);
while (1) {
if (timeout_set(5.0)) {
const char *const errmsg = strerror(errno);
fprintf(stderr, "Cannot set timeout: %s.\n", errmsg);
return 1;
}
len = getline(&line, &size, stdin);
if (len == (ssize_t)-1)
break;
if (len < (ssize_t)1) {
/* This should never occur (except for -1, of course). */
errno = EIO;
break;
}
/* We do not want *output* to be interrupted,
* so we cancel the timeout. */
timeout_unset();
if (fwrite(line, (size_t)len, 1, stdout) != 1) {
fprintf(stderr, "Error writing to standard output.\n");
fflush(stderr);
return 1;
}
fflush(stdout);
/* Next line. */
}
/* Remember to cancel the timeout. Also check it. */
if (timeout_unset())
fprintf(stderr, "Timed out.\n");
else
if (ferror(stdin) || !feof(stdin))
fprintf(stderr, "Error reading standard input.\n");
else
fprintf(stderr, "End of input.\n");
fflush(stderr);
/* Free line buffer. */
free(line);
line = NULL;
size = 0;
/* Done. */
return 0;
}
If you save the above as timer.c, you can compile it using e.g.
gcc -W -Wall -O3 -std=c99 -pedantic timer.c -lrt -o timer
and run it using ./timer.
If you read the code above carefully, you'll see that it is actually a periodic timer signal (at millisecond intervals), with a variable delay before the first signal. That is just a technique I like to use to make sure I don't miss the signal. (The signal repeats until the timeout is unset.)
Note that although you can do computation in an signal handler, you should only use functions that are async-signal-safe; see man 7 signal. Also, only the sig_atomic_t type is atomic wrt. normal single-threaded code and a signal handler. So, it is better to just use the signal as an indicator, and do the actual code in your own program.
If you wanted to e.g. update monster coordinates in a signal handler, it is possible but a bit tricky. I'd use three arrays containing the monster information, and use GCC __sync_bool_compare_and_swap() to update the array pointers -- very much the same technique as triple-buffering in graphics.
If you need more than one concurrent timeout, you could use multiple timers (there is a number of them available), but the best option is to define timeout slots. (You can use generation counters to detect "forgotten" timeouts, and so on.) Whenever a new timeout is set or unset, you update the timeout to reflect the next timeout that expires. It's a bit more code, but really a straightforward extension of the above.

Resources