Skip to content

Commit

Permalink
Invoked function and callback function can now accept a context point…
Browse files Browse the repository at this point in the history
…er (breaking change)
  • Loading branch information
sagiegurari committed Nov 19, 2020
1 parent ea1d272 commit fa2626e
Show file tree
Hide file tree
Showing 11 changed files with 155 additions and 28 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## CHANGELOG

### v0.2.0 (2020-11-20)

* Invoked function and callback function can now accept a context pointer (breaking change).

### v0.1.3 (2020-11-07)

* Internal functions are now namespaced with _forever prefix.
Expand Down
21 changes: 17 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,25 @@ The provided function is invoked as a forked process, so any crash is caught and
#include <unistd.h>


void my_program()
void my_program(void *context)
{
if (context != NULL)
{
// do something with the context
}

sleep(1);
exit(0);
}


int callback(const unsigned char started, int stat_loc)
int callback(void *context, const unsigned char started, int stat_loc)
{
if (context != NULL)
{
// do something with the context
}

if (stat_loc == 0 || !started)
{
return(-1); // no more retries
Expand All @@ -50,23 +60,26 @@ int callback(const unsigned char started, int stat_loc)

int main()
{
void *context = NULL;

// call 'my_program' and when it ends/crashes invoke it again, up
// to 10 times and wait 250 millies between invocations.
// counter will hold the amount of times 'my_program' was invoked.
unsigned int counter = forever_with_options(
my_program, // function to invoke
context, // context that is passed to the function on every invocation
10, // max amount of retries. 0 for unlimited retries.
250 // amount of millies to wait between invocations. 0 for no wait.
);

printf("Invoked %u time/s.\n", counter);

// call 'my_program' and when it ends/crashes call the provided callback
counter = forever_with_callback(my_program, callback);
counter = forever_with_callback(my_program, context, callback);
printf("Invoked %u time/s.\n", counter);

// run with unlimited retries and no delay between invocations
forever(my_program);
forever(my_program, context);
}
```
Expand Down
21 changes: 17 additions & 4 deletions examples/example.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,25 @@
#include <unistd.h>


void my_program()
void my_program(void *context)
{
if (context != NULL)
{
// do something with the context
}

sleep(1);
exit(0);
}


int callback(const unsigned char started, int stat_loc)
int callback(void *context, const unsigned char started, int stat_loc)
{
if (context != NULL)
{
// do something with the context
}

if (stat_loc == 0 || !started)
{
return(-1); // no more retries
Expand All @@ -24,21 +34,24 @@ int callback(const unsigned char started, int stat_loc)

int main()
{
void *context = NULL;

// call 'my_program' and when it ends/crashes invoke it again, up
// to 10 times and wait 250 millies between invocations.
// counter will hold the amount of times 'my_program' was invoked.
unsigned int counter = forever_with_options(
my_program, // function to invoke
context, // context that is passed to the function on every invocation
10, // max amount of retries. 0 for unlimited retries.
250 // amount of millies to wait between invocations. 0 for no wait.
);

printf("Invoked %u time/s.\n", counter);

// call 'my_program' and when it ends/crashes call the provided callback
counter = forever_with_callback(my_program, callback);
counter = forever_with_callback(my_program, context, callback);
printf("Invoked %u time/s.\n", counter);

// run with unlimited retries and no delay between invocations
forever(my_program);
forever(my_program, context);
}
6 changes: 3 additions & 3 deletions include/forever.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#ifndef __FOREVER_H__
#define __FOREVER_H__

unsigned int forever(void (*fn)());
unsigned int forever_with_options(void (*fn)(), const unsigned int /* max retries */, const unsigned int /* interval between invocations in milliseconds */);
unsigned int forever_with_callback(void (*fn)(), int (*callback)(const unsigned char, int));
unsigned int forever(void (*fn)(void *), void *);
unsigned int forever_with_options(void (*fn)(void *), void *, const unsigned int /* max retries */, const unsigned int /* interval between invocations in milliseconds */);
unsigned int forever_with_callback(void (*fn)(void *), void *, int (*callback)(void *, const unsigned char, int));

#endif

21 changes: 12 additions & 9 deletions src/forever.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,32 @@

struct ForeverState
{
void *context;
unsigned int max_retries;
unsigned int interval_in_millies;
int (*callback)(const unsigned char, int);
int (*callback)(void *, const unsigned char, int);
bool use_callback;
unsigned int invocation_counter;
bool stop;
};

// private functions
unsigned int _forever(void (*fn)(), struct ForeverState);
unsigned int _forever(void (*fn)(void *), struct ForeverState);
void _forever_on_exit(struct ForeverState *, const bool, int);
void _forever_msleep(unsigned int);


unsigned int forever(void (*fn)())
unsigned int forever(void (*fn)(void *), void *context)
{
return(forever_with_options(fn, 0, 0));
return(forever_with_options(fn, context, 0, 0));
}


unsigned int forever_with_options(void (*fn)(), const unsigned int max_retries, const unsigned int interval_in_millies)
unsigned int forever_with_options(void (*fn)(void *), void *context, const unsigned int max_retries, const unsigned int interval_in_millies)
{
struct ForeverState state =
{
context,
max_retries,
interval_in_millies,
NULL,
Expand All @@ -43,10 +45,11 @@ unsigned int forever_with_options(void (*fn)(), const unsigned int max_retries,
}


unsigned int forever_with_callback(void (*fn)(), int (*callback)(const unsigned char, int))
unsigned int forever_with_callback(void (*fn)(void *), void *context, int (*callback)(void *, const unsigned char, int))
{
struct ForeverState state =
{
context,
0,
0,
callback,
Expand All @@ -59,7 +62,7 @@ unsigned int forever_with_callback(void (*fn)(), int (*callback)(const unsigned
}


unsigned int _forever(void (*fn)(), struct ForeverState state)
unsigned int _forever(void (*fn)(void *), struct ForeverState state)
{
state.invocation_counter = 0;
state.stop = 0;
Expand All @@ -84,7 +87,7 @@ unsigned int _forever(void (*fn)(), struct ForeverState state)
}
else
{
(*fn)();
(*fn)(state.context);
return(0);
}
}
Expand All @@ -101,7 +104,7 @@ void _forever_on_exit(struct ForeverState *state, const bool started, int stat_l
if (state->use_callback)
{
const unsigned char started_flag = started ? 1 : 0;
const int interval_in_millies = state->callback(started_flag, stat_loc);
const int interval_in_millies = state->callback(state->context, started_flag, stat_loc);
if (interval_in_millies < 0)
{
state->stop = true;
Expand Down
5 changes: 3 additions & 2 deletions tests/test_callback_multiple_retries.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
unsigned short global_counter = 0;


int callback(const unsigned char started, int stat_loc)
int callback(void *context, const unsigned char started, int stat_loc)
{
assert_true(context == NULL);
assert_true(started);
assert_num_equal(stat_loc, 0);

Expand All @@ -31,7 +32,7 @@ void fn()
void test_impl()
{
clock_t time = clock();
unsigned int counter = forever_with_callback(fn, callback);
unsigned int counter = forever_with_callback(fn, NULL, callback);

assert_num_equal(counter, 4);
assert_true(clock() - time >= 2);
Expand Down
53 changes: 53 additions & 0 deletions tests/test_callback_with_context.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include "forever.h"
#include "test.h"
#include <stdlib.h>
#include <time.h>

struct Context
{
int counter;
};


int callback(void *context, const unsigned char started, int stat_loc)
{
((struct Context *)context)->counter++;
assert_true(started);
assert_num_equal(stat_loc, 0);

if (((struct Context *)context)->counter < 4)
{
return(500);
}

return(-1);
}


void fn(void *context)
{
assert_true(context != NULL);
exit(0);
}


void test_impl()
{
struct Context *context = malloc(sizeof(struct Context));

context->counter = 0;

clock_t time = clock();
unsigned int counter = forever_with_callback(fn, context, callback);
free(context);

assert_num_equal(counter, 4);
assert_true(clock() - time >= 2);
}


int main()
{
test_run(test_impl);
}

5 changes: 3 additions & 2 deletions tests/test_options_multiple_retries.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@
#include <stdlib.h>


void fn()
void fn(void *context)
{
assert_true(context == NULL);
exit(0);
}


void test_impl()
{
unsigned int counter = forever_with_options(fn, 10, 1);
unsigned int counter = forever_with_options(fn, NULL, 10, 1);

assert_num_equal(counter, 10);
}
Expand Down
5 changes: 3 additions & 2 deletions tests/test_options_single_retry.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@
#include <stdlib.h>


void fn()
void fn(void *context)
{
assert_true(context == NULL);
exit(0);
}


void test_impl()
{
unsigned int counter = forever_with_options(fn, 1, 0);
unsigned int counter = forever_with_options(fn, NULL, 1, 0);

assert_num_equal(counter, 1);
}
Expand Down
37 changes: 37 additions & 0 deletions tests/test_options_with_context.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include "forever.h"
#include "test.h"
#include <stdlib.h>

struct Context
{
int counter;
};


void fn(void *context)
{
((struct Context *)context)->counter++;
exit(0);
}


void test_impl()
{
struct Context *context = malloc(sizeof(struct Context));

context->counter = 0;

unsigned int counter = forever_with_options(fn, context, 10, 1);

assert_num_equal(counter, 10);
assert_num_equal(context->counter, 0);

free(context);
}


int main()
{
test_run(test_impl);
}

5 changes: 3 additions & 2 deletions tests/test_options_with_delay.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
#include <unistd.h>


void fn()
void fn(void *context)
{
assert_true(context == NULL);
sleep(1);
exit(0);
}
Expand All @@ -15,7 +16,7 @@ void fn()
void test_impl()
{
clock_t time = clock();
unsigned int counter = forever_with_options(fn, 2, 1000);
unsigned int counter = forever_with_options(fn, NULL, 2, 1000);

assert_num_equal(counter, 2);
assert_true(clock() - time >= 4);
Expand Down

0 comments on commit fa2626e

Please sign in to comment.