LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   how to properly use settimmer? (https://www.linuxquestions.org/questions/programming-9/how-to-properly-use-settimmer-4175611650/)

BW-userx 08-09-2017 08:37 PM

how to properly use settimmer?
 
ok I am willing to learn how to make this work. :D


I can get my program to work on the cli. changing the image at a given time, now i just want to autotomize it to be able to set a time for it to call for another file to load off a (linked) list within the program.

I got the timer to cycle in some separate code using seconds, ( converting it to minutes after I get it to actually work), then I dropped it in my main code,

I've tried this about 5 different ways its getting late here so I'm posting my last attempt.

Code:

if (opts.cycletime > 0)
{

printf("LOAD IMAGE %d\n", opts.cycletime);
// get_next_name_in_list();
//        filename = MH_FILE(filelist->data)->filename;
filename = set_timer();
printf("%s\n",filename);

}
else
{
 get_next_name_in_list();
filename = MH_FILE(filelist->data)->filename;
}

this is off a switch in getopts. value is set and converted into a unsigned int. or
Code:

unsigned int cycletime;
here:
Code:

case 201:
  printf("%s\n", optarg);
  opts.cycletime = atoi(optarg);
  printf("opt yitme %d\n", opts.cycletime);
  break;

it gets checked here then called to set the time after setting the first image,
Code:

char *set_timer(void)
{
 struct sigaction sa;
 struct itimerval timer;

 unsigned int whattime;
 char *tempfile;

 whattime =  opts.cycletime;
 printf("time %d\n",whattime);

// call to list to get next file
 get_next_name_in_list();
 tempfile = MH_FILE(filelist->data)->filename;

 /* Install timer_handler as the signal handler for SIGVTALRM. */
 memset (&sa, 0, sizeof (sa));
 sa.sa_handler = &timer_handler;
 sigaction (SIGVTALRM, &sa, NULL);

 /* Configure the timer to expire after 250 msec... */
 timer.it_value.tv_sec = 1;
 timer.it_value.tv_usec = 0;
 /* ... and every 250 msec after that. */
 timer.it_interval.tv_sec = whattime;
 timer.it_interval.tv_usec = 0;
 printf("time 2 %d\n",whattime);
 /* Start a virtual timer. It counts down whenever this process is
  executing. */
 setitimer ( ITIMER_REAL, &timer, NULL);
 
  return(tempfile);

  /* Do busy work. */
 while ( opts.cycletime > 0);

  return(tempfile);

}

It sends an image filename from the return and it loads and displays in the background, I just cannot at this time figure out how to get it to do it again, after the first call.

rtmistler 08-10-2017 08:21 AM

You are properly using setitimer(), the comments do not match the timer values, you are using 1 second for the first timeout value and then whatever is in the value of 'whattime' for the repeat timeout values.

You don't show your timer handler.

I have code which does work, which uses SIGALRM, which may or may not be the same numerical value for the SIG you are using. Or multiple signals may also occur at timeout.

Those are really the technical differences I notice in what you're using. Not sure if they're enough where things won't work, just that the timeouts are not 250 mS as your comment states. They can't be when you're using the tv_sec portion of the structure. Use the tv_usec and if the value is 250,000 then it will be 250 mSec.

Next, my timer_handler() increments a counter. My main loop checks that counter against a value and once it overflows, it will do the desired action, and it will reset the counter. The timer_handler() runs forever, always just incrementing the counter.

Additional thought is that say my desired time is 1/2 of a second, or 500 mSec. My timer_handler() function, run by my itimer, actually runs at maybe 20 mSec. The timer_handler() increments a counter each time. So my main loop checks that count to see if it exceeds a value of 25. Because 25 times 20 mSec works out to be 500 mSec. That's how I do it versus allowing the itimer to give me a single event.

It might be more helpful for you to not edit your posts. Because you asked an initial question, you've worked through it, and then you edit your post and no one can tell if your first question is still a question.

BW-userx 08-10-2017 09:05 AM

Quote:

Originally Posted by rtmistler (Post 5746692)
You are properly using setitimer(), the comments do not match the timer values, you are using 1 second for the first timeout value and then whatever is in the value of 'whattime' for the repeat timeout values.

You don't show your timer handler.

I have code which does work, which uses SIGALRM, which may or may not be the same numerical value for the SIG you are using. Or multiple signals may also occur at timeout.

Those are really the technical differences I notice in what you're using. Not sure if they're enough where things won't work, just that the timeouts are not 250 mS as your comment states. They can't be when you're using the tv_sec portion of the structure. Use the tv_usec and if the value is 250,000 then it will be 250 mSec.

Next, my timer_handler() increments a counter. My main loop checks that counter against a value and once it overflows, it will do the desired action, and it will reset the counter. The timer_handler() runs forever, always just incrementing the counter.

Additional thought is that say my desired time is 1/2 of a second, or 500 mSec. My timer_handler() function, run by my itimer, actually runs at maybe 20 mSec. The timer_handler() increments a counter each time. So my main loop checks that count to see if it exceeds a value of 25. Because 25 times 20 mSec works out to be 500 mSec. That's how I do it versus allowing the itimer to give me a single event.

It might be more helpful for you to not edit your posts. Because you asked an initial question, you've worked through it, and then you edit your post and no one can tell if your first question is still a question.

Good morning, because that is what time it is here, first things first LQ, and replies,

this is where I got that code

http://www.informit.com/articles/art...3618&seqNum=14

and yeah I was having a hard time figuring out how this thing worked, because the handler is not called in that body of code, at least I could not see it using the function call timer_handler(int varName); and probably still am because I have not yet played with it as of yet.

As this is off the net example, It looked like it will suit my purposes,so why write another one?.

When running it in a separate main where the body of the code was in main, and the time handler as posted in here - I put that in too, and not seeing it actually calling the function within the code confused me, but I added it to mine none the less in the same file that the set-timer is in then made a different function to be call within it, thinking maybe that is how this thing is working, still got nothing. the seconds I was using because that is what they are there for to, to use seconds instead of milliseconds - it doesn't have to be that precise.


So i was just fiddling with it to see what the times do to get it down to seconds instead. the first one is to set it to wait time, and the second one is to set it to how long before repeating, that was my understanding of it. so 1 sec wait time, then whatever the user put it in the command line to set it to minutes, that has not been converted yet, but converting seconds is easier then milliseconds less zeros to count. so I was just using seconds for trial,

sorry I was in a bit of a hurry posting this,
the setting are just to see if i can get it to work, one second wait times any faster and imlib will not have time to load and display an image.

Code:


 unsigned int whattime; <- next time place holder
 whattime =  opts.cycletime; <-- how it is passed to it

// Configure the timer to expire after 1 second

 timer.it_value.tv_sec = 1; <-- one second to start

 timer.it_value.tv_usec = 0; <-- not being used so zero.

// then again every X=seconds after that.

 timer.it_interval.tv_sec = whattime; <- set here by whatever the user puts in the command line.
                                          testing is set to use just seconds

 timer.it_interval.tv_usec = 0; <- not used because seconds is short / fast enough -

 printf("time 2 %d\n",whattime);

the rest of that code is in the first post. I tried timer.it_interval.tv_usec with it being commented out and only using seconds but it would not work at all in the other main I was testing it in. So I put them back and set them to zero and it started working again.


still needs to be set to minutes (whattime * 60) but that can wait until I get it to work first.

Code:

void timer_handler (int signum)
{
 cycle_images();
 printf ("timer fired\n");

this was in the loadimage.c file where if it was called then the name would not need to be passed in a return.
Code:


void cycle_images(void)
{
    printf("load image cycle time %d \n", opts.cycletime);
    get_next_name_in_list();
    filename = MH_FILE(filelist->data)->filename;
    printf("file-> %s\n", filename);
}

so maybe it just has to be where I am putting the functions
timer_handler
set_timer
are in the same c file,
cycle_images()
is in the file where the list is called so it will not need a return value, though I may have to go back and double check that to be sure.

after I post this I am going to go back and chew on what you posed some more.
MOD:
I know it has to be some little simple mistake, as I call cycle_images() from main too, just to see if it pulls a filename from that function to be passed to the loadimage function to set the image to the desktop, and it gets a filename,
Code:

in main cycle images <-- printf just before the  cycle_images function call
load image cycle time 3
file-> /media/data/test/128/Heidy-Pino-001-0750.png <-- out put from that function.

it still does not seem to work, because no images are changing on the desktop. or more output from printf in the terminal indicating it is being called again.

thanks.

rtmistler 08-10-2017 10:03 AM

Quote:

Originally Posted by BW-userx (Post 5746706)
Good morning, because that is what time it is here, first things first LQ, and replies

It's morning here too, just a tad later :)
Quote:

Originally Posted by BW-userx (Post 5746706)
and yeah I was having a hard time figuring out how this thing worked, because the handler is not called in that body of code, at least I could not see it using the function call timer_handler(int varName); and probably still am because I have not yet played with it as of yet.

timer_handler() is called when the itimer expires, because this is part of the sa structure when you defined the timer.
Quote:

Originally Posted by BW-userx (Post 5746706)
As this is off the net example, It looked like it will suit my purposes,so why write another one?

Totally agree, however one always should learn from the Internet examples and understand where you need to alter it for your needs. You're getting there, don't worry.

When running it in a separate main where the body of the code was in main, and the time handler as posted in here - I put that in too, and not seeing it actually calling the function within the code confused me, but I added it to mine none the less in the same file that the set-timer is in then made a different function to be call within it, thinking maybe that is how this thing is working, still got nothing. the seconds I was using because that is what they are there for to, to use seconds instead of milliseconds - it doesn't have to be that precise.

As far as the rest of what you've discussed, and your concern about running the updates to the UI, how about you verify that the timing is correct, that the timeouts do occur and getting that part correct, before you worry about whether or not it is calling your update function.

BW-userx 08-10-2017 10:21 AM

Quote:

Originally Posted by rtmistler (Post 5746722)
It's morning here too, just a tad later :)timer_handler() is called when the itimer expires, because this is part of the sa structure when you defined the timer.Totally agree, however one always should learn from the Internet examples and understand where you need to alter it for your needs. You're getting there, don't worry.

When running it in a separate main where the body of the code was in main, and the time handler as posted in here - I put that in too, and not seeing it actually calling the function within the code confused me, but I added it to mine none the less in the same file that the set-timer is in then made a different function to be call within it, thinking maybe that is how this thing is working, still got nothing. the seconds I was using because that is what they are there for to, to use seconds instead of milliseconds - it doesn't have to be that precise.

As far as the rest of what you've discussed, and your concern about running the updates to the UI, how about you verify that the timing is correct, that the timeouts do occur and getting that part correct, before you worry about whether or not it is calling your update function.

this is what I just did using that example. I put it in a different function then called it in main.
Code:

#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>

void timer_handler (int signum)
{
 static int count = 0;
 printf ("timer expired %d times\n", ++count);
}

void timer_setting(int elapstime){

 struct sigaction sa;
 struct itimerval timer;

 /* Install timer_handler as the signal handler for SIGVTALRM. */
 memset (&sa, 0, sizeof (sa));
 sa.sa_handler = &timer_handler;
 sigaction (SIGVTALRM, &sa, NULL);

 /* Configure the timer to expire after 250 msec... */

 timer.it_value.tv_sec = 1; <-- set to start after 1 sec
 timer.it_value.tv_usec = 0;

 /* ... and every 250 msec after that. */

 timer.it_interval.tv_sec = elapstime; <--- TIME (seconds)  gets set here from prams
 timer.it_interval.tv_usec = 0;

 /* Start a virtual timer. It counts down whenever this process is
  executing. */

 setitimer (ITIMER_VIRTUAL, &timer, NULL);

 /* Do busy work. */
 while (1);
}

int main ()
{
timer_setting(3);
return 0;
}

which worked, then when I changed ITIMER_VIRTUAL to ITIMER_REAL it only ran one time then stopped, though using ITIMER_VIRTUAL definitely is not actually one second because of its nature, it is not real time, it for whatever its reasons kept working, the results:
Code:

//with ITIMER_REAL
userx%slackwhere ⚡ bin ⚡> gcc settimer.c -o timer2
userx%slackwhere ⚡ bin ⚡> ./timer2                                                                         
Alarm clock

// with ITIMER_VIRTUAL
userx%slackwhere ⚡ bin ⚡> gcc settimer.c -o timer2
userx%slackwhere ⚡ bin ⚡> ./timer2                                                                         
timer expired 1 times
timer expired 2 times
timer expired 3 times
timer expired 4 times

SO I am going to try changing it to ITIMER_VIRTUAL in my main code and see if that does the trick.

rtmistler 08-10-2017 10:46 AM

I use ITIMER_REAL and it works fine for me. However you go with what works and try to explain it by reading the man pages.

And actually here is the difference, which is something I already mentioned (courtesy setitimer(2)):
Quote:

ITIMER_REAL
decrements in real time, and delivers SIGALRM upon expiration.
ITIMER_VIRTUAL
decrements only when the process is executing, and delivers SIGVTALRM upon expiration.

My recommendation is always that people review the manual pages properly when they are using new functions.

BW-userx 08-10-2017 11:27 AM

Quote:

Originally Posted by rtmistler (Post 5746736)
I use ITIMER_REAL and it works fine for me. However you go with what works and try to explain it by reading the man pages.

And actually here is the difference, which is something I already mentioned (courtesy setitimer(2)):My recommendation is always that people review the manual pages properly when they are using new functions.

yeah I am reading this right now
GNU Basic Signal Handling
https://www.gnu.org/software/libc/ma...-Handling.html

just to complaine for a minute,
Code:

This is the type of signal handler functions. Signal handlers take one integer argument specifying the signal number,
and have return type void. So, you should define handler functions like this:

void handler (int signum) { … } <-- I guess do something within that body between the brackets.

but when calling that handler function in another file, I ran it in the test main file.
Code:

void timer_handler (int signum)
{

printf("signum%d\n",signum);
 static int count = 0;
 printf ("timer expired %d times\n", ++count);
}

//results

timer expired 2 times
signum26 <--

but there is no declared int for signum to work, so I am guessing it is just out there in la la linux land OS somewhere to get magically pulled into but not associated with anything.
Code:



// To load normally - orginal Image sizes
int load_image(ImageMode mode, int alpha, int use_filelist)
{
int signum2;

int left = 0, top = 0, x = 0, y = 0, imgW = 0, imgH = 0;

if (opts.cycletime > 0)
{
// get_next_name_in_list();
//filename = MH_FILE(filelist->data)->filename;
//filename = set_timer();

  set_timer(opts.cycletime);
  printf("set_time called in load image\n");

  get_next_name_in_list();
  filename = MH_FILE(filelist->data)->filename;
  printf("cycle time Load image -> %s\n",filename);
       
  timer_handler (signum2); <-- figuring out what variable name to pass in there is got me stuck because I keep getting errors.

  printf("IMGLOAD TIMER HANDLER\n");

}
 else
 {
  get_next_name_in_list();
filename = MH_FILE(filelist->data)->filename;
}

.....
}

because the way I see it when you take everything out of main where it is globally set, one still needs to call the timer_handler function like all of the other functions in order for them to be utilized within the code.

anyways I found a different way and it worked but it does not release the program in the terminal
Code:

typedef void (*sighandler_t)(int);

void timer_handler (int signum)
{
 static int count = 0;
 cycle_images();
 printf ("timer expired %d times\n", ++count);
}




void set_timer(int changetime)
{


struct timeval my_value={1,0};
struct timeval my_interval={changetime,0};

struct itimerval my_timer={my_interval,my_value};

setitimer(ITIMER_REAL, &my_timer, 0);

signal(SIGALRM, (sighandler_t) timer_handler);
while(1);
}

I'm going to scrap this and read and seek and read on the different ways to do this as it looks like many.

rigor 08-14-2017 06:33 PM

Context & Trivial example, via Inter-Dimensional Portal
 
From "Linux La-La Land" :-)

First, the Context, signal numbers and the types of events to which they correspond. On various Linux-en, Cygwin, and various other environments, it is possible to do this from the command line:
Code:

this is a command prompt > kill -l
 1) SIGHUP      2) SIGINT      3) SIGQUIT      4) SIGILL      5) SIGTRAP
 6) SIGABRT      7) SIGBUS      8) SIGFPE      9) SIGKILL    10) SIGUSR1
11) SIGSEGV    12) SIGUSR2    13) SIGPIPE    14) SIGALRM    15) SIGTERM
16) SIGSTKFLT  17) SIGCHLD    18) SIGCONT    19) SIGSTOP    20) SIGTSTP
21) SIGTTIN    22) SIGTTOU    23) SIGURG      24) SIGXCPU    25) SIGXFSZ
26) SIGVTALRM  27) SIGPROF    28) SIGWINCH    29) SIGIO      30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

Alternatively, from /usr/include/bits/signum.h:
Code:

/* Signals.  */
#define SIGHUP          1      /* Hangup (POSIX).  */
#define SIGINT          2      /* Interrupt (ANSI).  */
#define SIGQUIT        3      /* Quit (POSIX).  */
#define SIGILL          4      /* Illegal instruction (ANSI).  */
#define SIGTRAP        5      /* Trace trap (POSIX).  */
#define SIGABRT        6      /* Abort (ANSI).  */
#define SIGIOT          6      /* IOT trap (4.2 BSD).  */
#define SIGBUS          7      /* BUS error (4.2 BSD).  */
#define SIGFPE          8      /* Floating-point exception (ANSI).  */
#define SIGKILL        9      /* Kill, unblockable (POSIX).  */
#define SIGUSR1        10      /* User-defined signal 1 (POSIX).  */
#define SIGSEGV        11      /* Segmentation violation (ANSI).  */
#define SIGUSR2        12      /* User-defined signal 2 (POSIX).  */
#define SIGPIPE        13      /* Broken pipe (POSIX).  */
#define SIGALRM        14      /* Alarm clock (POSIX).  */
#define SIGTERM        15      /* Termination (ANSI).  */
#define SIGSTKFLT      16      /* Stack fault.  */
#define SIGCLD          SIGCHLD /* Same as SIGCHLD (System V).  */
#define SIGCHLD        17      /* Child status has changed (POSIX).  */
#define SIGCONT        18      /* Continue (POSIX).  */
#define SIGSTOP        19      /* Stop, unblockable (POSIX).  */
#define SIGTSTP        20      /* Keyboard stop (POSIX).  */
#define SIGTTIN        21      /* Background read from tty (POSIX).  */
#define SIGTTOU        22      /* Background write to tty (POSIX).  */
#define SIGURG          23      /* Urgent condition on socket (4.2 BSD).  */
#define SIGXCPU        24      /* CPU limit exceeded (4.2 BSD).  */
#define SIGXFSZ        25      /* File size limit exceeded (4.2 BSD).  */
#define SIGVTALRM      26      /* Virtual alarm clock (4.2 BSD).  */
#define SIGPROF        27      /* Profiling alarm clock (4.2 BSD).  */
#define SIGWINCH        28      /* Window size change (4.3 BSD, Sun).  */
#define SIGPOLL        SIGIO  /* Pollable event occurred (System V).  */
#define SIGIO          29      /* I/O now possible (4.2 BSD).  */
#define SIGPWR          30      /* Power failure restart (System V).  */
#define SIGSYS          31      /* Bad system call.  */
#define SIGUNUSED      31

#define _NSIG          65      /* Biggest signal number + 1
                                  (including real-time signals).  */

A simple program, as a trivial example of setitimer() usage:
Code:

/*  setitimer_use.c  */

# include <stdio.h>
# include <stdlib.h>
# include <sys/time.h>
# include <string.h>
# include <signal.h>

# define TRUE  (  1  ==  1  )



void usage(  char *prog_name  )
{
    fprintf(  stderr,  "Usage:  %s  integer_delay_in_seconds\n" ,  prog_name  ) ;
   
    exit(  EXIT_FAILURE ) ;
}



void signal_handler(  sig_num  )
{
    printf(  "\nGot Sig, Sig was '%s'.\n\n" ,  strsignal( sig_num )  ) ;
}



int main(  int argc ,  char *argv[]  )
{
    struct sigaction    sig_handling ;
    struct itimerval    interval ;
    int                seconds ;


    if (  argc  !=  2  )
        usage(  argv[0]  ) ;

   
    if (  strspn( argv[1] ,  "0123456789" )  !=  strlen( argv[1] )  )
        usage(  argv[0]  ) ;

    seconds = atoi(  argv[1]  ) ;
   
    interval.it_interval.tv_sec = interval.it_value.tv_sec = seconds ;
    interval.it_interval.tv_usec = interval.it_value.tv_usec = 0 ;
   
    sig_handling.sa_handler =  signal_handler ;

    if (  setitimer( ITIMER_REAL ,  &interval ,  NULL )  !=  0  )
    {
        perror(  argv[0]  ) ;
       
        exit(  EXIT_FAILURE  ) ;
    }
   
    sigaction(  SIGALRM ,  &sig_handling ,  NULL  ) ;

    while(  TRUE  )
    {
        pause() ;
    }
}

After compiling and running, here's the output:
Code:

this is a command prompt > setitimer_use 2

Got Sig, Sig was 'Alarm clock'.


Got Sig, Sig was 'Alarm clock'.


Got Sig, Sig was 'Alarm clock'.


Got Sig, Sig was 'Alarm clock'.


Got Sig, Sig was 'Alarm clock'.


Got Sig, Sig was 'Alarm clock'.


Got Sig, Sig was 'Alarm clock'.


Got Sig, Sig was 'Alarm clock'.


Got Sig, Sig was 'Alarm clock'.


Got Sig, Sig was 'Alarm clock'.


Got Sig, Sig was 'Alarm clock'.


Got Sig, Sig was 'Alarm clock'.


Got Sig, Sig was 'Alarm clock'.


Got Sig, Sig was 'Alarm clock'.

^C

HTH.


All times are GMT -5. The time now is 12:18 AM.