check: Import version 0.9.14

This lifts the files almost verbatim (the changes being running though
gst-indent and fixing the FSF address) from the upstream respository.
Therefore this commit reverts some GStreamer-specific patches to check
that will be reintroduced next.

Fixes https://bugzilla.gnome.org/show_bug.cgi?id=727826
This commit is contained in:
Sebastian Rasmussen 2014-11-15 12:53:32 +01:00 committed by Sebastian Dröge
parent f1c2cd60c3
commit f1df7aba8f
27 changed files with 2571 additions and 805 deletions

View file

@ -0,0 +1,8 @@
#include "libcompat.h"
unsigned int
alarm (unsigned int seconds CK_ATTRIBUTE_UNUSED)
{
assert (0);
return 0;
}

View file

@ -18,12 +18,13 @@
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "../lib/libcompat.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <math.h>
#include "check.h"
#include "check_error.h"
@ -31,14 +32,18 @@
#include "check_impl.h"
#include "check_msg.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h> /* for _POSIX_VERSION */
#endif
#ifndef DEFAULT_TIMEOUT
#define DEFAULT_TIMEOUT 4
#endif
/*
* When a process exits either normally, with exit(), or
* by an uncaught signal, The lower 0x377 bits are passed
* to the parent. Of those, only the lower 8 bits are
* returned by the WEXITSTATUS() macro.
*/
#define WEXITSTATUS_MASK 0xFF
int check_major_version = CHECK_MAJOR_VERSION;
int check_minor_version = CHECK_MINOR_VERSION;
int check_micro_version = CHECK_MICRO_VERSION;
@ -55,7 +60,8 @@ Suite *
suite_create (const char *name)
{
Suite *s;
s = emalloc (sizeof (Suite)); /* freed in suite_free */
s = (Suite *) emalloc (sizeof (Suite)); /* freed in suite_free */
if (name == NULL)
s->name = "";
else
@ -64,17 +70,37 @@ suite_create (const char *name)
return s;
}
int
suite_tcase (Suite * s, const char *tcname)
{
List *l;
TCase *tc;
if (s == NULL)
return 0;
l = s->tclst;
for (check_list_front (l); !check_list_at_end (l); check_list_advance (l)) {
tc = (TCase *) check_list_val (l);
if (strcmp (tcname, tc->name) == 0)
return 1;
}
return 0;
}
static void
suite_free (Suite * s)
{
List *l;
if (s == NULL)
return;
l = s->tclst;
for (list_front (l); !list_at_end (l); list_advance (l)) {
tcase_free (list_val (l));
for (check_list_front (l); !check_list_at_end (l); check_list_advance (l)) {
tcase_free ((TCase *) check_list_val (l));
}
list_free (s->tclst);
check_list_free (s->tclst);
free (s);
}
@ -82,8 +108,10 @@ TCase *
tcase_create (const char *name)
{
char *env;
int timeout = DEFAULT_TIMEOUT;
TCase *tc = emalloc (sizeof (TCase)); /*freed in tcase_free */
double timeout_sec = DEFAULT_TIMEOUT;
TCase *tc = (TCase *) emalloc (sizeof (TCase)); /*freed in tcase_free */
if (name == NULL)
tc->name = "";
else
@ -91,21 +119,28 @@ tcase_create (const char *name)
env = getenv ("CK_DEFAULT_TIMEOUT");
if (env != NULL) {
int tmp = atoi (env);
if (tmp >= 0) {
timeout = tmp;
char *endptr = NULL;
double tmp = strtod (env, &endptr);
if (tmp >= 0 && endptr != env && (*endptr) == '\0') {
timeout_sec = tmp;
}
}
env = getenv ("CK_TIMEOUT_MULTIPLIER");
if (env != NULL) {
int tmp = atoi (env);
if (tmp >= 0) {
timeout = timeout * tmp;
char *endptr = NULL;
double tmp = strtod (env, &endptr);
if (tmp >= 0 && endptr != env && (*endptr) == '\0') {
timeout_sec = timeout_sec * tmp;
}
}
tc->timeout = timeout;
tc->timeout.tv_sec = (time_t) floor (timeout_sec);
tc->timeout.tv_nsec =
(long) ((timeout_sec - floor (timeout_sec)) * (double) NANOS_PER_SECONDS);
tc->tflst = check_list_create ();
tc->unch_sflst = check_list_create ();
tc->ch_sflst = check_list_create ();
@ -119,16 +154,16 @@ tcase_create (const char *name)
static void
tcase_free (TCase * tc)
{
list_apply (tc->tflst, free);
list_apply (tc->unch_sflst, free);
list_apply (tc->ch_sflst, free);
list_apply (tc->unch_tflst, free);
list_apply (tc->ch_tflst, free);
list_free (tc->tflst);
list_free (tc->unch_sflst);
list_free (tc->ch_sflst);
list_free (tc->unch_tflst);
list_free (tc->ch_tflst);
check_list_apply (tc->tflst, free);
check_list_apply (tc->unch_sflst, free);
check_list_apply (tc->ch_sflst, free);
check_list_apply (tc->unch_tflst, free);
check_list_apply (tc->ch_tflst, free);
check_list_free (tc->tflst);
check_list_free (tc->unch_sflst);
check_list_free (tc->ch_sflst);
check_list_free (tc->unch_tflst);
check_list_free (tc->ch_tflst);
free (tc);
}
@ -138,7 +173,7 @@ suite_add_tcase (Suite * s, TCase * tc)
{
if (s == NULL || tc == NULL)
return;
list_add_end (s->tclst, tc);
check_list_add_end (s->tclst, tc);
}
void
@ -146,23 +181,25 @@ _tcase_add_test (TCase * tc, TFun fn, const char *name, int _signal,
int allowed_exit_value, int start, int end)
{
TF *tf;
if (tc == NULL || fn == NULL || name == NULL)
return;
tf = emalloc (sizeof (TF)); /* freed in tcase_free */
tf = (TF *) emalloc (sizeof (TF)); /* freed in tcase_free */
tf->fn = fn;
tf->loop_start = start;
tf->loop_end = end;
tf->signal = _signal; /* 0 means no signal expected */
tf->allowed_exit_value = allowed_exit_value; /* 0 is default successful exit */
tf->allowed_exit_value = (WEXITSTATUS_MASK & allowed_exit_value); /* 0 is default successful exit */
tf->name = name;
list_add_end (tc->tflst, tf);
check_list_add_end (tc->tflst, tf);
}
static Fixture *
fixture_create (SFun fun, int ischecked)
{
Fixture *f;
f = emalloc (sizeof (Fixture));
f = (Fixture *) emalloc (sizeof (Fixture));
f->fun = fun;
f->ischecked = ischecked;
@ -186,33 +223,48 @@ tcase_add_fixture (TCase * tc, SFun setup, SFun teardown, int ischecked)
{
if (setup) {
if (ischecked)
list_add_end (tc->ch_sflst, fixture_create (setup, ischecked));
check_list_add_end (tc->ch_sflst, fixture_create (setup, ischecked));
else
list_add_end (tc->unch_sflst, fixture_create (setup, ischecked));
check_list_add_end (tc->unch_sflst, fixture_create (setup, ischecked));
}
/* Add teardowns at front so they are run in reverse order. */
if (teardown) {
if (ischecked)
list_add_front (tc->ch_tflst, fixture_create (teardown, ischecked));
check_list_add_front (tc->ch_tflst, fixture_create (teardown, ischecked));
else
list_add_front (tc->unch_tflst, fixture_create (teardown, ischecked));
check_list_add_front (tc->unch_tflst,
fixture_create (teardown, ischecked));
}
}
void
tcase_set_timeout (TCase * tc, int timeout)
tcase_set_timeout (TCase * tc, double timeout)
{
#if defined(HAVE_FORK)
if (timeout >= 0) {
char *env = getenv ("CK_TIMEOUT_MULTIPLIER");
if (env != NULL) {
int tmp = atoi (env);
if (tmp >= 0) {
char *endptr = NULL;
double tmp = strtod (env, &endptr);
if (tmp >= 0 && endptr != env && (*endptr) == '\0') {
timeout = timeout * tmp;
}
}
tc->timeout = timeout;
tc->timeout.tv_sec = (time_t) floor (timeout);
tc->timeout.tv_nsec =
(long) ((timeout - floor (timeout)) * (double) NANOS_PER_SECONDS);
}
#else
(void) tc;
(void) timeout;
eprintf
("This version does not support timeouts, as fork is not supported",
__FILE__, __LINE__);
#endif /* HAVE_FORK */
}
void
@ -230,44 +282,57 @@ _mark_point (const char *file, int line)
}
void
_fail_unless (int result, const char *file, int line, const char *expr, ...)
_ck_assert_failed (const char *file, int line, const char *expr, ...)
{
const char *msg;
send_loc_info (file, line);
if (!result) {
va_list ap;
char buf[BUFSIZ];
send_loc_info (file, line);
va_start (ap, expr);
msg = (const char *) va_arg (ap, char *);
if (msg == NULL)
msg = expr;
vsnprintf (buf, BUFSIZ, msg, ap);
va_end (ap);
send_failure_info (buf);
if (cur_fork_status () == CK_FORK) {
#ifdef _POSIX_VERSION
#if defined(HAVE_FORK) && HAVE_FORK==1
_exit (1);
#endif /* _POSIX_VERSION */
}
#endif /* HAVE_FORK */
} else {
longjmp (error_jmp_buffer, 1);
}
}
SRunner *
srunner_create (Suite * s)
{
SRunner *sr = emalloc (sizeof (SRunner)); /* freed in srunner_free */
SRunner *sr = (SRunner *) emalloc (sizeof (SRunner)); /* freed in srunner_free */
sr->slst = check_list_create ();
if (s != NULL)
list_add_end (sr->slst, s);
sr->stats = emalloc (sizeof (TestStats)); /* freed in srunner_free */
check_list_add_end (sr->slst, s);
sr->stats = (TestStats *) emalloc (sizeof (TestStats)); /* freed in srunner_free */
sr->stats->n_checked = sr->stats->n_failed = sr->stats->n_errors = 0;
sr->resultlst = check_list_create ();
sr->log_fname = NULL;
sr->xml_fname = NULL;
sr->tap_fname = NULL;
sr->loglst = NULL;
#if defined(HAVE_FORK)
sr->fstat = CK_FORK_GETENV;
#else
/*
* Overriding the default of running tests in fork mode,
* as this system does not have fork()
*/
sr->fstat = CK_NOFORK;
#endif /* HAVE_FORK */
return sr;
}
@ -277,7 +342,7 @@ srunner_add_suite (SRunner * sr, Suite * s)
if (s == NULL)
return;
list_add_end (sr->slst, s);
check_list_add_end (sr->slst, s);
}
void
@ -285,24 +350,23 @@ srunner_free (SRunner * sr)
{
List *l;
TestResult *tr;
if (sr == NULL)
return;
free (sr->stats);
l = sr->slst;
for (list_front (l); !list_at_end (l); list_advance (l)) {
suite_free (list_val (l));
for (check_list_front (l); !check_list_at_end (l); check_list_advance (l)) {
suite_free ((Suite *) check_list_val (l));
}
list_free (sr->slst);
check_list_free (sr->slst);
l = sr->resultlst;
for (list_front (l); !list_at_end (l); list_advance (l)) {
tr = list_val (l);
free (tr->file);
free (tr->msg);
free (tr);
for (check_list_front (l); !check_list_at_end (l); check_list_advance (l)) {
tr = (TestResult *) check_list_val (l);
tr_free (tr);
}
list_free (sr->resultlst);
check_list_free (sr->resultlst);
free (sr);
}
@ -325,11 +389,16 @@ srunner_failures (SRunner * sr)
int i = 0;
TestResult **trarray;
List *rlst;
trarray = malloc (sizeof (trarray[0]) * srunner_ntests_failed (sr));
trarray =
(TestResult **) emalloc (sizeof (trarray[0]) *
srunner_ntests_failed (sr));
rlst = sr->resultlst;
for (list_front (rlst); !list_at_end (rlst); list_advance (rlst)) {
TestResult *tr = list_val (rlst);
for (check_list_front (rlst); !check_list_at_end (rlst);
check_list_advance (rlst)) {
TestResult *tr = (TestResult *) check_list_val (rlst);
if (non_pass (tr->rtype))
trarray[i++] = tr;
@ -344,11 +413,13 @@ srunner_results (SRunner * sr)
TestResult **trarray;
List *rlst;
trarray = malloc (sizeof (trarray[0]) * srunner_ntests_run (sr));
trarray =
(TestResult **) emalloc (sizeof (trarray[0]) * srunner_ntests_run (sr));
rlst = sr->resultlst;
for (list_front (rlst); !list_at_end (rlst); list_advance (rlst)) {
trarray[i++] = list_val (rlst);
for (check_list_front (rlst); !check_list_at_end (rlst);
check_list_advance (rlst)) {
trarray[i++] = (TestResult *) check_list_val (rlst);
}
return trarray;
}
@ -364,17 +435,11 @@ tr_create (void)
{
TestResult *tr;
tr = emalloc (sizeof (TestResult));
tr = (TestResult *) emalloc (sizeof (TestResult));
tr_init (tr);
return tr;
}
void
tr_reset (TestResult * tr)
{
tr_init (tr);
}
static void
tr_init (TestResult * tr)
{
@ -385,6 +450,15 @@ tr_init (TestResult * tr)
tr->file = NULL;
tr->tcname = NULL;
tr->tname = NULL;
tr->duration = -1;
}
void
tr_free (TestResult * tr)
{
free (tr->file);
free (tr->msg);
free (tr);
}
@ -424,7 +498,7 @@ tr_tcname (TestResult * tr)
return tr->tcname;
}
static int _fstat = CK_FORK;
static enum fork_status _fstat = CK_FORK;
void
set_fork_status (enum fork_status fstat)
@ -440,3 +514,41 @@ cur_fork_status (void)
{
return _fstat;
}
/**
* Not all systems support the same clockid_t's. This call checks
* if the CLOCK_MONOTONIC clockid_t is valid. If so, that is returned,
* otherwise, CLOCK_REALTIME is returned.
*
* The clockid_t that was found to work on the first call is
* cached for subsequent calls.
*/
clockid_t
check_get_clockid ()
{
static clockid_t clockid = -1;
if (clockid == -1) {
/*
* Only check if we have librt available. Otherwise, the clockid
* will be ignored anyway, as the clock_gettime() and
* timer_create() functions will be re-implemented in libcompat.
* Worse, if librt and alarm() are unavailable, this check
* will result in an assert(0).
*/
#ifdef HAVE_LIBRT
timer_t timerid;
if (timer_create (CLOCK_MONOTONIC, NULL, &timerid) == 0) {
timer_delete (timerid);
clockid = CLOCK_MONOTONIC;
} else {
clockid = CLOCK_REALTIME;
}
#else
clockid = CLOCK_MONOTONIC;
#endif
}
return clockid;
}

File diff suppressed because it is too large Load diff

View file

@ -18,22 +18,29 @@
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "../lib/libcompat.h"
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <setjmp.h>
#include "check_error.h"
/**
* Storage for setjmp/longjmp context information used in NOFORK mode
*/
jmp_buf error_jmp_buffer;
/* FIXME: including a colon at the end is a bad way to indicate an error */
void
eprintf (const char *fmt, const char *file, int line, ...)
{
va_list args;
fflush (stderr);
fprintf (stderr, "%s:%d: ", file, line);
@ -53,6 +60,7 @@ void *
emalloc (size_t n)
{
void *p;
p = malloc (n);
if (p == NULL)
eprintf ("malloc of %u bytes failed:", __FILE__, __LINE__ - 2, n);
@ -63,6 +71,7 @@ void *
erealloc (void *ptr, size_t n)
{
void *p;
p = realloc (ptr, n);
if (p == NULL)
eprintf ("realloc of %u bytes failed:", __FILE__, __LINE__ - 2, n);

View file

@ -21,11 +21,18 @@
#ifndef ERROR_H
#define ERROR_H
#include "../lib/libcompat.h"
#include <setjmp.h>
extern jmp_buf error_jmp_buffer;
/* Include stdlib.h beforehand */
/* Print error message and die
If fmt ends in colon, include system error information */
void eprintf (const char *fmt, const char *file, int line,...);
void
eprintf (const char *fmt, const char *file, int line, ...)
CK_ATTRIBUTE_NORETURN;
/* malloc or die */
void *emalloc (size_t n);
void *erealloc (void *, size_t n);

View file

@ -21,22 +21,31 @@
#ifndef CHECK_IMPL_H
#define CHECK_IMPL_H
/* This header should be included by any module that needs
to know the implementation details of the check structures
Include stdio.h & list.h before this header
Include stdio.h, time.h, & list.h before this header
*/
typedef struct TF {
#define US_PER_SEC 1000000
#define NANOS_PER_SECONDS 1000000000
/** calculate the difference in useconds out of two "struct timespec"s */
#define DIFF_IN_USEC(begin, end) \
( (((end).tv_sec - (begin).tv_sec) * US_PER_SEC) + \
((end).tv_nsec/1000) - ((begin).tv_nsec/1000) )
typedef struct TF
{
TFun fn;
int loop_start;
int loop_end;
const char *name;
int signal;
unsigned char allowed_exit_value;
signed char allowed_exit_value;
} TF;
struct Suite {
struct Suite
{
const char *name;
List *tclst; /* List of test cases */
};
@ -47,9 +56,10 @@ typedef struct Fixture
SFun fun;
} Fixture;
struct TCase {
struct TCase
{
const char *name;
int timeout;
struct timespec timeout;
List *tflst; /* list of test functions */
List *unch_sflst;
List *unch_tflst;
@ -57,18 +67,21 @@ struct TCase {
List *ch_tflst;
};
typedef struct TestStats {
typedef struct TestStats
{
int n_checked;
int n_failed;
int n_errors;
} TestStats;
struct TestResult {
struct TestResult
{
enum test_result rtype; /* Type of result */
enum ck_result_ctx ctx; /* When the result occurred */
char *file; /* File where the test occured */
int line; /* Line number where the test occurred */
int iter; /* The iteration value for looping tests */
int duration; /* duration of this test in microseconds */
const char *tcname; /* Test case that generated the result */
const char *tname; /* Test that generated the result */
char *msg; /* Failure message */
@ -76,34 +89,39 @@ struct TestResult {
TestResult *tr_create (void);
void tr_reset (TestResult * tr);
void tr_free (TestResult * tr);
enum cl_event {
CLINITLOG_SR,
CLENDLOG_SR,
CLSTART_SR,
CLSTART_S,
CLEND_SR,
CLEND_S,
enum cl_event
{
CLINITLOG_SR, /* Initialize log file */
CLENDLOG_SR, /* Tests are complete */
CLSTART_SR, /* Suite runner start */
CLSTART_S, /* Suite start */
CLEND_SR, /* Suite runner end */
CLEND_S, /* Suite end */
CLSTART_T, /* A test case is about to run */
CLEND_T
CLEND_T /* Test case end */
};
typedef void (*LFun) (SRunner *, FILE *, enum print_output,
void *, enum cl_event);
typedef struct Log {
typedef struct Log
{
FILE *lfile;
LFun lfun;
int close;
enum print_output mode;
} Log;
struct SRunner {
struct SRunner
{
List *slst; /* List of Suite objects */
TestStats *stats; /* Run statistics */
List *resultlst; /* List of unit test results */
const char *log_fname; /* name of log file */
const char *xml_fname; /* name of xml output file */
const char *tap_fname; /* name of tap output file */
List *loglst; /* list of Log objects */
enum fork_status fstat; /* controls if suites are forked or not
NOTE: Don't use this value directly,
@ -114,4 +132,6 @@ struct SRunner {
void set_fork_status (enum fork_status fstat);
enum fork_status cur_fork_status (void);
clockid_t check_get_clockid (void);
#endif /* CHECK_IMPL_H */

View file

@ -18,7 +18,7 @@
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "../lib/libcompat.h"
#include <stdlib.h>
#include <string.h>
@ -35,11 +35,11 @@ enum
struct List
{
int n_elts;
int max_elts;
unsigned int n_elts;
unsigned int max_elts;
int current; /* pointer to the current node */
int last; /* pointer to the node before END */
const void **data;
void **data;
};
static void
@ -47,7 +47,8 @@ maybe_grow (List * lp)
{
if (lp->n_elts >= lp->max_elts) {
lp->max_elts *= LGROW;
lp->data = erealloc (lp->data, lp->max_elts * sizeof (lp->data[0]));
lp->data =
(void **) erealloc (lp->data, lp->max_elts * sizeof (lp->data[0]));
}
}
@ -55,16 +56,17 @@ List *
check_list_create (void)
{
List *lp;
lp = emalloc (sizeof (List));
lp = (List *) emalloc (sizeof (List));
lp->n_elts = 0;
lp->max_elts = LINIT;
lp->data = emalloc (sizeof (lp->data[0]) * LINIT);
lp->data = (void **) emalloc (sizeof (lp->data[0]) * LINIT);
lp->current = lp->last = -1;
return lp;
}
void
list_add_front (List * lp, const void *val)
check_list_add_front (List * lp, void *val)
{
if (lp == NULL)
return;
@ -77,7 +79,7 @@ list_add_front (List * lp, const void *val)
}
void
list_add_end (List * lp, const void *val)
check_list_add_end (List * lp, void *val)
{
if (lp == NULL)
return;
@ -89,7 +91,7 @@ list_add_end (List * lp, const void *val)
}
int
list_at_end (List * lp)
check_list_at_end (List * lp)
{
if (lp->current == -1)
return 1;
@ -98,7 +100,7 @@ list_at_end (List * lp)
}
void
list_front (List * lp)
check_list_front (List * lp)
{
if (lp->current == -1)
return;
@ -107,7 +109,7 @@ list_front (List * lp)
void
list_free (List * lp)
check_list_free (List * lp)
{
if (lp == NULL)
return;
@ -117,34 +119,34 @@ list_free (List * lp)
}
void *
list_val (List * lp)
check_list_val (List * lp)
{
if (lp == NULL)
return NULL;
if (lp->current == -1 || lp->current > lp->last)
return NULL;
return (void *) lp->data[lp->current];
return lp->data[lp->current];
}
void
list_advance (List * lp)
check_list_advance (List * lp)
{
if (lp == NULL)
return;
if (list_at_end (lp))
if (check_list_at_end (lp))
return;
lp->current++;
}
void
list_apply (List * lp, void (*fp) (void *))
check_list_apply (List * lp, void (*fp) (void *))
{
if (lp == NULL || fp == NULL)
return;
for (list_front (lp); !list_at_end (lp); list_advance (lp))
fp (list_val (lp));
for (check_list_front (lp); !check_list_at_end (lp); check_list_advance (lp))
fp (check_list_val (lp));
}

View file

@ -27,30 +27,30 @@ typedef struct List List;
List *check_list_create (void);
/* Is list at end? */
int list_at_end (List * lp);
int check_list_at_end (List * lp);
/* Position list at front */
void list_front(List *lp);
void check_list_front (List * lp);
/* Add a value to the front of the list,
positioning newly added value as current value.
More expensive than list_add_end, as it uses memmove. */
void list_add_front (List *lp, const void *val);
void check_list_add_front (List * lp, void *val);
/* Add a value to the end of the list,
positioning newly added value as current value */
void list_add_end (List *lp, const void *val);
void check_list_add_end (List * lp, void *val);
/* Give the value of the current node */
void *list_val (List * lp);
void *check_list_val (List * lp);
/* Position the list at the next node */
void list_advance (List * lp);
void check_list_advance (List * lp);
/* Free a list, but don't free values */
void list_free (List * lp);
void check_list_free (List * lp);
void list_apply (List *lp, void (*fp) (void *));
void check_list_apply (List * lp, void (*fp) (void *));
#endif /* CHECK_LIST_H */

View file

@ -18,16 +18,12 @@
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "../lib/libcompat.h"
#include <stdlib.h>
#include <stdio.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <time.h>
#include <check.h>
#if HAVE_SUBUNIT_CHILD_H
#if ENABLE_SUBUNIT
#include <subunit/child.h>
#endif
@ -38,20 +34,11 @@
#include "check_print.h"
#include "check_str.h"
/* localtime_r is apparently not available on Windows */
#ifndef HAVE_LOCALTIME_R
static struct tm *
localtime_r (const time_t * clock, struct tm *result)
{
struct tm *now = localtime (clock);
if (now == NULL) {
return NULL;
} else {
*result = *now;
}
return result;
}
#endif /* HAVE_DECL_LOCALTIME_R */
/*
* If a log file is specified to be "-", then instead of
* opening a file the log output is printed to stdout.
*/
#define STDOUT_OVERRIDE_LOG_FILE_NAME "-"
static void srunner_send_evt (SRunner * sr, void *obj, enum cl_event evt);
@ -66,13 +53,17 @@ srunner_set_log (SRunner * sr, const char *fname)
int
srunner_has_log (SRunner * sr)
{
return sr->log_fname != NULL;
return srunner_log_fname (sr) != NULL;
}
const char *
srunner_log_fname (SRunner * sr)
{
/* check if log filename have been set explicitly */
if (sr->log_fname != NULL)
return sr->log_fname;
return getenv ("CK_LOG_FILE_NAME");
}
@ -87,20 +78,50 @@ srunner_set_xml (SRunner * sr, const char *fname)
int
srunner_has_xml (SRunner * sr)
{
return sr->xml_fname != NULL;
return srunner_xml_fname (sr) != NULL;
}
const char *
srunner_xml_fname (SRunner * sr)
{
/* check if XML log filename have been set explicitly */
if (sr->xml_fname != NULL) {
return sr->xml_fname;
}
return getenv ("CK_XML_LOG_FILE_NAME");
}
void
srunner_set_tap (SRunner * sr, const char *fname)
{
if (sr->tap_fname)
return;
sr->tap_fname = fname;
}
int
srunner_has_tap (SRunner * sr)
{
return srunner_tap_fname (sr) != NULL;
}
const char *
srunner_tap_fname (SRunner * sr)
{
/* check if tap log filename have been set explicitly */
if (sr->tap_fname != NULL) {
return sr->tap_fname;
}
return getenv ("CK_TAP_LOG_FILE_NAME");
}
void
srunner_register_lfun (SRunner * sr, FILE * lfile, int close,
LFun lfun, enum print_output printmode)
{
Log *l = emalloc (sizeof (Log));
Log *l = (Log *) emalloc (sizeof (Log));
if (printmode == CK_ENV) {
printmode = get_env_printmode ();
@ -110,7 +131,7 @@ srunner_register_lfun (SRunner * sr, FILE * lfile, int close,
l->lfun = lfun;
l->close = close;
l->mode = printmode;
list_add_end (sr->loglst, l);
check_list_add_end (sr->loglst, l);
return;
}
@ -142,6 +163,7 @@ void
log_test_start (SRunner * sr, TCase * tc, TF * tfun)
{
char buffer[100];
snprintf (buffer, 99, "%s:%s", tc->name, tfun->name);
srunner_send_evt (sr, buffer, CLSTART_T);
}
@ -157,9 +179,10 @@ srunner_send_evt (SRunner * sr, void *obj, enum cl_event evt)
{
List *l;
Log *lg;
l = sr->loglst;
for (list_front (l); !list_at_end (l); list_advance (l)) {
lg = list_val (l);
for (check_list_front (l); !check_list_at_end (l); check_list_advance (l)) {
lg = (Log *) check_list_val (l);
fflush (lg->lfile);
lg->lfun (sr, lg->lfile, lg->mode, obj, evt);
fflush (lg->lfile);
@ -172,10 +195,6 @@ stdout_lfun (SRunner * sr, FILE * file, enum print_output printmode,
{
Suite *s;
if (printmode == CK_ENV) {
printmode = get_env_printmode ();
}
switch (evt) {
case CLINITLOG_SR:
break;
@ -187,7 +206,7 @@ stdout_lfun (SRunner * sr, FILE * file, enum print_output printmode,
}
break;
case CLSTART_S:
s = obj;
s = (Suite *) obj;
if (printmode > CK_SILENT) {
fprintf (file, " %s\n", s->name);
}
@ -202,7 +221,6 @@ stdout_lfun (SRunner * sr, FILE * file, enum print_output printmode,
}
break;
case CLEND_S:
s = obj;
break;
case CLSTART_T:
break;
@ -231,7 +249,7 @@ lfile_lfun (SRunner * sr, FILE * file,
case CLSTART_SR:
break;
case CLSTART_S:
s = obj;
s = (Suite *) obj;
fprintf (file, "Running suite %s\n", s->name);
break;
case CLEND_SR:
@ -239,12 +257,11 @@ lfile_lfun (SRunner * sr, FILE * file,
srunner_fprint (file, sr, CK_MINIMAL);
break;
case CLEND_S:
s = obj;
break;
case CLSTART_T:
break;
case CLEND_T:
tr = obj;
tr = (TestResult *) obj;
tr_fprint (file, tr, CK_VERBOSE);
break;
default:
@ -261,47 +278,60 @@ xml_lfun (SRunner * sr CK_ATTRIBUTE_UNUSED, FILE * file,
{
TestResult *tr;
Suite *s;
static struct timeval inittv, endtv;
static struct timespec ts_start = { 0, 0 };
static char t[sizeof "yyyy-mm-dd hh:mm:ss"] = { 0 };
if (t[0] == 0) {
struct timeval inittv;
struct tm now;
gettimeofday (&inittv, NULL);
localtime_r (&(inittv.tv_sec), &now);
clock_gettime (check_get_clockid (), &ts_start);
if (localtime_r ((const time_t *) &(inittv.tv_sec), &now) != NULL) {
strftime (t, sizeof ("yyyy-mm-dd hh:mm:ss"), "%Y-%m-%d %H:%M:%S", &now);
}
}
switch (evt) {
case CLINITLOG_SR:
fprintf (file, "<?xml version=\"1.0\"?>\n");
fprintf (file,
"<?xml-stylesheet type=\"text/xsl\" href=\"http://check.sourceforge.net/xml/check_unittest.xslt\"?>\n");
fprintf (file,
"<testsuites xmlns=\"http://check.sourceforge.net/ns\">\n");
fprintf (file, " <datetime>%s</datetime>\n", t);
break;
case CLENDLOG_SR:
gettimeofday (&endtv, NULL);
fprintf (file, " <duration>%f</duration>\n",
(endtv.tv_sec + (float) (endtv.tv_usec) / 1000000) -
(inittv.tv_sec + (float) (inittv.tv_usec / 1000000)));
{
struct timespec ts_end = { 0, 0 };
unsigned long duration;
/* calculate time the test were running */
clock_gettime (check_get_clockid (), &ts_end);
duration = (unsigned long) DIFF_IN_USEC (ts_start, ts_end);
fprintf (file, " <duration>%lu.%06lu</duration>\n",
duration / US_PER_SEC, duration % US_PER_SEC);
fprintf (file, "</testsuites>\n");
}
break;
case CLSTART_SR:
break;
case CLSTART_S:
s = obj;
s = (Suite *) obj;
fprintf (file, " <suite>\n");
fprintf (file, " <title>%s</title>\n", s->name);
fprintf (file, " <title>");
fprint_xml_esc (file, s->name);
fprintf (file, "</title>\n");
break;
case CLEND_SR:
break;
case CLEND_S:
fprintf (file, " </suite>\n");
s = obj;
break;
case CLSTART_T:
break;
case CLEND_T:
tr = obj;
tr = (TestResult *) obj;
tr_xmlprint (file, tr, CK_VERBOSE);
break;
default:
@ -310,13 +340,55 @@ xml_lfun (SRunner * sr CK_ATTRIBUTE_UNUSED, FILE * file,
}
void
tap_lfun (SRunner * sr CK_ATTRIBUTE_UNUSED, FILE * file,
enum print_output printmode CK_ATTRIBUTE_UNUSED, void *obj,
enum cl_event evt)
{
TestResult *tr;
static int num_tests_run = 0;
switch (evt) {
case CLINITLOG_SR:
/* As this is a new log file, reset the number of tests executed */
num_tests_run = 0;
break;
case CLENDLOG_SR:
/* Output the test plan as the last line */
fprintf (file, "1..%d\n", num_tests_run);
fflush (file);
break;
case CLSTART_SR:
break;
case CLSTART_S:
break;
case CLEND_SR:
break;
case CLEND_S:
break;
case CLSTART_T:
break;
case CLEND_T:
/* Print the test result to the tap file */
num_tests_run += 1;
tr = (TestResult *) obj;
fprintf (file, "%s %d - %s:%s:%s: %s\n",
tr->rtype == CK_PASS ? "ok" : "not ok", num_tests_run,
tr->file, tr->tcname, tr->tname, tr->msg);
fflush (file);
break;
default:
eprintf ("Bad event type received in tap_lfun", __FILE__, __LINE__);
}
}
#if ENABLE_SUBUNIT
void
subunit_lfun (SRunner * sr, FILE * file, enum print_output printmode,
void *obj, enum cl_event evt)
{
TestResult *tr;
Suite *s;
char const *name;
/* assert(printmode == CK_SUBUNIT); */
@ -329,7 +401,6 @@ subunit_lfun (SRunner * sr, FILE * file, enum print_output printmode,
case CLSTART_SR:
break;
case CLSTART_S:
s = obj;
break;
case CLEND_SR:
if (printmode > CK_SILENT) {
@ -338,17 +409,17 @@ subunit_lfun (SRunner * sr, FILE * file, enum print_output printmode,
}
break;
case CLEND_S:
s = obj;
break;
case CLSTART_T:
name = obj;
name = (const char *) obj;
subunit_test_start (name);
break;
case CLEND_T:
tr = obj;
tr = (TestResult *) obj;
{
char *name = ck_strdup_printf ("%s:%s", tr->tcname, tr->tname);
char *msg = tr_short_str (tr);
switch (tr->rtype) {
case CK_PASS:
subunit_test_pass (name);
@ -359,6 +430,7 @@ subunit_lfun (SRunner * sr, FILE * file, enum print_output printmode,
case CK_ERROR:
subunit_test_error (name, msg);
break;
case CK_TEST_RESULT_INVALID:
default:
eprintf ("Bad result type in subunit_lfun", __FILE__, __LINE__);
free (name);
@ -372,15 +444,30 @@ subunit_lfun (SRunner * sr, FILE * file, enum print_output printmode,
}
#endif
static FILE *
srunner_open_file (const char *filename)
{
FILE *f = NULL;
if (strcmp (filename, STDOUT_OVERRIDE_LOG_FILE_NAME) == 0) {
f = stdout;
} else {
f = fopen (filename, "w");
if (f == NULL) {
eprintf ("Error in call to fopen while opening file %s:", __FILE__,
__LINE__ - 2, filename);
}
}
return f;
}
FILE *
srunner_open_lfile (SRunner * sr)
{
FILE *f = NULL;
if (srunner_has_log (sr)) {
f = fopen (sr->log_fname, "w");
if (f == NULL)
eprintf ("Error in call to fopen while opening log file %s:", __FILE__,
__LINE__ - 2, sr->log_fname);
f = srunner_open_file (srunner_log_fname (sr));
}
return f;
}
@ -389,11 +476,20 @@ FILE *
srunner_open_xmlfile (SRunner * sr)
{
FILE *f = NULL;
if (srunner_has_xml (sr)) {
f = fopen (sr->xml_fname, "w");
if (f == NULL)
eprintf ("Error in call to fopen while opening xml file %s:", __FILE__,
__LINE__ - 2, sr->xml_fname);
f = srunner_open_file (srunner_xml_fname (sr));
}
return f;
}
FILE *
srunner_open_tapfile (SRunner * sr)
{
FILE *f = NULL;
if (srunner_has_tap (sr)) {
f = srunner_open_file (srunner_tap_fname (sr));
}
return f;
}
@ -402,6 +498,7 @@ void
srunner_init_logging (SRunner * sr, enum print_output print_mode)
{
FILE *f;
sr->loglst = check_list_create ();
#if ENABLE_SUBUNIT
if (print_mode != CK_SUBUNIT)
@ -413,11 +510,15 @@ srunner_init_logging (SRunner * sr, enum print_output print_mode)
#endif
f = srunner_open_lfile (sr);
if (f) {
srunner_register_lfun (sr, f, 1, lfile_lfun, print_mode);
srunner_register_lfun (sr, f, f != stdout, lfile_lfun, print_mode);
}
f = srunner_open_xmlfile (sr);
if (f) {
srunner_register_lfun (sr, f, 2, xml_lfun, print_mode);
srunner_register_lfun (sr, f, f != stdout, xml_lfun, print_mode);
}
f = srunner_open_tapfile (sr);
if (f) {
srunner_register_lfun (sr, f, f != stdout, tap_lfun, print_mode);
}
srunner_send_evt (sr, NULL, CLINITLOG_SR);
}
@ -431,16 +532,17 @@ srunner_end_logging (SRunner * sr)
srunner_send_evt (sr, NULL, CLENDLOG_SR);
l = sr->loglst;
for (list_front (l); !list_at_end (l); list_advance (l)) {
Log *lg = list_val (l);
for (check_list_front (l); !check_list_at_end (l); check_list_advance (l)) {
Log *lg = (Log *) check_list_val (l);
if (lg->close) {
rval = fclose (lg->lfile);
if (rval != 0)
eprintf ("Error in call to fclose while closing log file:", __FILE__,
__LINE__ - 2);
eprintf ("Error in call to fclose while closing log file:",
__FILE__, __LINE__ - 2);
}
free (lg);
}
list_free (l);
check_list_free (l);
sr->loglst = NULL;
}

View file

@ -37,6 +37,9 @@ void lfile_lfun (SRunner *sr, FILE *file, enum print_output,
void xml_lfun (SRunner * sr, FILE * file, enum print_output,
void *obj, enum cl_event evt);
void tap_lfun (SRunner * sr, FILE * file, enum print_output,
void *obj, enum cl_event evt);
void subunit_lfun (SRunner * sr, FILE * file, enum print_output,
void *obj, enum cl_event evt);
@ -45,6 +48,7 @@ void srunner_register_lfun (SRunner *sr, FILE *lfile, int close,
FILE *srunner_open_lfile (SRunner * sr);
FILE *srunner_open_xmlfile (SRunner * sr);
FILE *srunner_open_tapfile (SRunner * sr);
void srunner_init_logging (SRunner * sr, enum print_output print_mode);
void srunner_end_logging (SRunner * sr);

View file

@ -18,12 +18,9 @@
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "../lib/libcompat.h"
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
@ -34,6 +31,7 @@
#include "check_impl.h"
#include "check_msg.h"
#include "check_pack.h"
#include "check_str.h"
/* 'Pipe' is implemented as a temporary file to overcome message
@ -57,7 +55,9 @@
*/
static FILE *send_file1;
static char *send_file1_name;
static FILE *send_file2;
static char *send_file2_name;
static FILE *get_pipe (void);
static void setup_pipe (void);
@ -86,8 +86,18 @@ send_failure_info (const char *msg)
{
FailMsg fmsg;
fmsg.msg = (char *) msg;
ppack (fileno (get_pipe ()), CK_MSG_FAIL, (CheckMsg *) & fmsg);
fmsg.msg = strdup (msg);
ppack (get_pipe (), CK_MSG_FAIL, (CheckMsg *) & fmsg);
free (fmsg.msg);
}
void
send_duration_info (int duration)
{
DurationMsg dmsg;
dmsg.duration = duration;
ppack (get_pipe (), CK_MSG_DURATION, (CheckMsg *) & dmsg);
}
void
@ -95,9 +105,10 @@ send_loc_info (const char *file, int line)
{
LocMsg lmsg;
lmsg.file = (char *) file;
lmsg.file = strdup (file);
lmsg.line = line;
ppack (fileno (get_pipe ()), CK_MSG_LOC, (CheckMsg *) & lmsg);
ppack (get_pipe (), CK_MSG_LOC, (CheckMsg *) & lmsg);
free (lmsg.file);
}
void
@ -106,7 +117,7 @@ send_ctx_info (enum ck_result_ctx ctx)
CtxMsg cmsg;
cmsg.ctx = ctx;
ppack (fileno (get_pipe ()), CK_MSG_CTX, (CheckMsg *) & cmsg);
ppack (get_pipe (), CK_MSG_CTX, (CheckMsg *) & cmsg);
}
TestResult *
@ -117,10 +128,17 @@ receive_test_result (int waserror)
TestResult *result;
fp = get_pipe ();
if (fp == NULL)
if (fp == NULL) {
eprintf ("Error in call to get_pipe", __FILE__, __LINE__ - 2);
}
rewind (fp);
rmsg = punpack (fileno (fp));
rmsg = punpack (fp);
if (rmsg == NULL) {
eprintf ("Error in call to punpack", __FILE__, __LINE__ - 4);
}
teardown_pipe ();
setup_pipe ();
@ -156,7 +174,7 @@ construct_test_result (RcvMsg * rmsg, int waserror)
tr = tr_create ();
if (rmsg->msg != NULL || waserror) {
tr->ctx = (cur_fork_status () == CK_FORK) ? rmsg->lastctx : rmsg->failctx;
tr->ctx = rmsg->lastctx;
tr->msg = rmsg->msg;
rmsg->msg = NULL;
tr_set_loc_by_ctx (tr, tr->ctx, rmsg);
@ -167,6 +185,7 @@ construct_test_result (RcvMsg * rmsg, int waserror)
} else {
tr->ctx = CK_CTX_TEST;
tr->msg = NULL;
tr->duration = rmsg->duration;
tr_set_loc_by_ctx (tr, CK_CTX_TEST, rmsg);
}
@ -185,16 +204,67 @@ teardown_messaging (void)
teardown_pipe ();
}
/**
* Open a temporary file.
*
* If the file could be unlinked upon creation, the name
* of the file is not returned via 'name'. However, if the
* file could not be unlinked, the name is returned,
* expecting the caller to both delete the file and
* free the 'name' field after the file is closed.
*/
FILE *
open_tmp_file (char **name)
{
FILE *file;
*name = NULL;
/* Windows does not like tmpfile(). This is likely because tmpfile()
* call unlink() on the file before returning it, to make sure the
* file is deleted when it is closed. The unlink() call also fails
* on Windows if the file is still open. */
/* also note that mkstemp is apparently a C90 replacement for tmpfile */
/* perhaps all we need to do on Windows is set TMPDIR to whatever is
stored in TEMP for tmpfile to work */
/* and finally, the "b" from "w+b" is ignored on OS X, not sure about WIN32 */
file = tmpfile ();
if (file == NULL) {
char *tmp = getenv ("TEMP");
char *tmp_file = tempnam (tmp, "check_");
/*
* Note, tempnam is not enough to get a unique name. Between
* getting the name and opening the file, something else also
* calling tempnam() could get the same name. It has been observed
* on MinGW-w64 builds on Wine that this exact thing happens
* if multiple instances of a unit tests are running concurrently.
* To prevent two concurrent unit tests from getting the same file,
* we append the pid to the file. The pid should be unique on the
* system.
*/
char *uniq_tmp_file = ck_strdup_printf ("%s.%d", tmp_file, getpid ());
file = fopen (uniq_tmp_file, "w+b");
*name = uniq_tmp_file;
free (tmp_file);
}
return file;
}
static void
setup_pipe (void)
{
if (send_file1 != 0) {
if (send_file2 != 0)
eprintf ("Only one nesting of suite runs supported", __FILE__, __LINE__);
send_file2 = tmpfile ();
} else {
send_file1 = tmpfile ();
if (send_file1 == NULL) {
send_file1 = open_tmp_file (&send_file1_name);
return;
}
if (send_file2 == NULL) {
send_file2 = open_tmp_file (&send_file2_name);
return;
}
eprintf ("Only one nesting of suite runs supported", __FILE__, __LINE__);
}
static void
@ -203,9 +273,19 @@ teardown_pipe (void)
if (send_file2 != 0) {
fclose (send_file2);
send_file2 = 0;
if (send_file2_name != NULL) {
unlink (send_file2_name);
free (send_file2_name);
send_file2_name = NULL;
}
} else if (send_file1 != 0) {
fclose (send_file1);
send_file1 = 0;
if (send_file1_name != NULL) {
unlink (send_file1_name);
free (send_file1_name);
send_file1_name = NULL;
}
} else {
eprintf ("No messaging setup", __FILE__, __LINE__);
}

View file

@ -27,10 +27,13 @@
void send_failure_info (const char *msg);
void send_loc_info (const char *file, int line);
void send_ctx_info (enum ck_result_ctx ctx);
void send_duration_info (int duration);
TestResult *receive_test_result (int waserror);
void setup_messaging (void);
void teardown_messaging (void);
FILE *open_tmp_file (char **name);
#endif /*CHECK_MSG_NEW_H */

View file

@ -18,32 +18,37 @@
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "../lib/libcompat.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "_stdint.h"
#include "check.h"
#include "check_error.h"
#include "check_list.h"
#include "check_impl.h"
#include "check_pack.h"
#ifdef HAVE_PTHREAD
#include <pthread.h>
pthread_mutex_t lock_mutex = PTHREAD_MUTEX_INITIALIZER;
#else
#ifndef HAVE_PTHREAD
#define pthread_mutex_lock(arg)
#define pthread_mutex_unlock(arg)
#define pthread_cleanup_push(f,a) {
#define pthread_cleanup_pop(e) }
#endif
/* Maximum size for one message in the message stream. */
#define CK_MAX_MSG_SIZE 8192
/* This is used to implement a sliding window on the receiving
* side. When sending messages, we assure that no single message
* is bigger than this (actually we check against CK_MAX_MSG_SIZE/2).
* The usual size for a message is less than 80 bytes.
* All this is done instead of the previous approach to allocate (actually
* continuously reallocate) one big chunk for the whole message stream.
* Problems were seen in the wild with up to 4 GB reallocations.
*/
/* typedef an unsigned int that has at least 4 bytes */
typedef uint32_t ck_uint32;
@ -56,15 +61,17 @@ static char *upack_str (char **buf);
static int pack_ctx (char **buf, CtxMsg * cmsg);
static int pack_loc (char **buf, LocMsg * lmsg);
static int pack_fail (char **buf, FailMsg * fmsg);
static int pack_duration (char **buf, DurationMsg * fmsg);
static void upack_ctx (char **buf, CtxMsg * cmsg);
static void upack_loc (char **buf, LocMsg * lmsg);
static void upack_fail (char **buf, FailMsg * fmsg);
static void upack_duration (char **buf, DurationMsg * fmsg);
static void check_type (int type, const char *file, int line);
static enum ck_msg_type upack_type (char **buf);
static void pack_type (char **buf, enum ck_msg_type type);
static int read_buf (int fdes, char **buf);
static int read_buf (FILE * fdes, int size, char *buf);
static int get_result (char *buf, RcvMsg * rmsg);
static void rcvmsg_update_ctx (RcvMsg * rmsg, enum ck_result_ctx ctx);
static void rcvmsg_update_loc (RcvMsg * rmsg, const char *file, int line);
@ -77,13 +84,15 @@ typedef void (*upfun) (char **, CheckMsg *);
static pfun pftab[] = {
(pfun) pack_ctx,
(pfun) pack_fail,
(pfun) pack_loc
(pfun) pack_loc,
(pfun) pack_duration
};
static upfun upftab[] = {
(upfun) upack_ctx,
(upfun) upack_fail,
(upfun) upack_loc
(upfun) upack_loc,
(upfun) upack_duration
};
int
@ -103,7 +112,6 @@ int
upack (char *buf, CheckMsg * msg, enum ck_msg_type *type)
{
char *obuf;
int nread;
if (buf == NULL)
return -1;
@ -116,8 +124,7 @@ upack (char *buf, CheckMsg * msg, enum ck_msg_type *type)
upftab[*type] (&buf, msg);
nread = buf - obuf;
return nread;
return buf - obuf;
}
static void
@ -126,10 +133,10 @@ pack_int (char **buf, int val)
unsigned char *ubuf = (unsigned char *) *buf;
ck_uint32 uval = val;
ubuf[0] = (uval >> 24) & 0xFF;
ubuf[1] = (uval >> 16) & 0xFF;
ubuf[2] = (uval >> 8) & 0xFF;
ubuf[3] = uval & 0xFF;
ubuf[0] = (unsigned char) ((uval >> 24) & 0xFF);
ubuf[1] = (unsigned char) ((uval >> 16) & 0xFF);
ubuf[2] = (unsigned char) ((uval >> 8) & 0xFF);
ubuf[3] = (unsigned char) (uval & 0xFF);
*buf += 4;
}
@ -140,7 +147,9 @@ upack_int (char **buf)
unsigned char *ubuf = (unsigned char *) *buf;
ck_uint32 uval;
uval = ((ubuf[0] << 24) | (ubuf[1] << 16) | (ubuf[2] << 8) | ubuf[3]);
uval =
(ck_uint32) ((ubuf[0] << 24) | (ubuf[1] << 16) | (ubuf[2] << 8) |
ubuf[3]);
*buf += 4;
@ -174,12 +183,12 @@ upack_str (char **buf)
strsz = upack_int (buf);
if (strsz > 0) {
val = emalloc (strsz + 1);
val = (char *) emalloc (strsz + 1);
memcpy (val, *buf, strsz);
val[strsz] = 0;
*buf += strsz;
} else {
val = emalloc (1);
val = (char *) emalloc (1);
*val = 0;
}
@ -206,7 +215,7 @@ pack_ctx (char **buf, CtxMsg * cmsg)
int len;
len = 4 + 4;
*buf = ptr = emalloc (len);
*buf = ptr = (char *) emalloc (len);
pack_type (&ptr, CK_MSG_CTX);
pack_int (&ptr, (int) cmsg->ctx);
@ -217,7 +226,28 @@ pack_ctx (char **buf, CtxMsg * cmsg)
static void
upack_ctx (char **buf, CtxMsg * cmsg)
{
cmsg->ctx = upack_int (buf);
cmsg->ctx = (enum ck_result_ctx) upack_int (buf);
}
static int
pack_duration (char **buf, DurationMsg * cmsg)
{
char *ptr;
int len;
len = 4 + 4;
*buf = ptr = (char *) emalloc (len);
pack_type (&ptr, CK_MSG_DURATION);
pack_int (&ptr, cmsg->duration);
return len;
}
static void
upack_duration (char **buf, DurationMsg * cmsg)
{
cmsg->duration = upack_int (buf);
}
static int
@ -227,7 +257,7 @@ pack_loc (char **buf, LocMsg * lmsg)
int len;
len = 4 + 4 + (lmsg->file ? strlen (lmsg->file) : 0) + 4;
*buf = ptr = emalloc (len);
*buf = ptr = (char *) emalloc (len);
pack_type (&ptr, CK_MSG_LOC);
pack_str (&ptr, lmsg->file);
@ -250,7 +280,7 @@ pack_fail (char **buf, FailMsg * fmsg)
int len;
len = 4 + 4 + (fmsg->msg ? strlen (fmsg->msg) : 0);
*buf = ptr = emalloc (len);
*buf = ptr = (char *) emalloc (len);
pack_type (&ptr, CK_MSG_FAIL);
pack_str (&ptr, fmsg->msg);
@ -272,54 +302,52 @@ check_type (int type, const char *file, int line)
}
#ifdef HAVE_PTHREAD
pthread_mutex_t mutex_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t ck_mutex_lock = PTHREAD_MUTEX_INITIALIZER;
static void
ppack_cleanup (void *mutex)
{
pthread_mutex_unlock ((pthread_mutex_t *) mutex);
}
#endif
void
ppack (int fdes, enum ck_msg_type type, CheckMsg * msg)
ppack (FILE * fdes, enum ck_msg_type type, CheckMsg * msg)
{
char *buf;
char *buf = NULL;
int n;
ssize_t r;
n = pack (type, &buf, msg);
pthread_mutex_lock (&mutex_lock);
r = write (fdes, buf, n);
pthread_mutex_unlock (&mutex_lock);
if (r == -1)
eprintf ("Error in call to write:", __FILE__, __LINE__ - 2);
/* Keep it on the safe side to not send too much data. */
if (n > (CK_MAX_MSG_SIZE / 2))
eprintf ("Message string too long", __FILE__, __LINE__ - 2);
pthread_cleanup_push (ppack_cleanup, &ck_mutex_lock);
pthread_mutex_lock (&ck_mutex_lock);
r = fwrite (buf, 1, n, fdes);
fflush (fdes);
pthread_mutex_unlock (&ck_mutex_lock);
pthread_cleanup_pop (0);
if (r != n)
eprintf ("Error in call to fwrite:", __FILE__, __LINE__ - 2);
free (buf);
}
static int
read_buf (int fdes, char **buf)
read_buf (FILE * fdes, int size, char *buf)
{
char *readloc;
int n;
int nread = 0;
int size = 1;
int grow = 2;
*buf = emalloc (size);
readloc = *buf;
while (1) {
n = read (fdes, readloc, size - nread);
if (n == 0)
break;
if (n == -1)
eprintf ("Error in call to read:", __FILE__, __LINE__ - 4);
n = fread (buf, 1, size, fdes);
nread += n;
size *= grow;
*buf = erealloc (*buf, size);
readloc = *buf + nread;
if (ferror (fdes)) {
eprintf ("Error in call to fread:", __FILE__, __LINE__ - 4);
}
return nread;
return n;
}
static int
get_result (char *buf, RcvMsg * rmsg)
{
@ -333,23 +361,29 @@ get_result (char *buf, RcvMsg * rmsg)
if (type == CK_MSG_CTX) {
CtxMsg *cmsg = (CtxMsg *) & msg;
rcvmsg_update_ctx (rmsg, cmsg->ctx);
} else if (type == CK_MSG_LOC) {
LocMsg *lmsg = (LocMsg *) & msg;
if (rmsg->failctx == CK_CTX_INVALID) {
rcvmsg_update_loc (rmsg, lmsg->file, lmsg->line);
}
free (lmsg->file);
} else if (type == CK_MSG_FAIL) {
FailMsg *fmsg = (FailMsg *) & msg;
if (rmsg->msg == NULL) {
rmsg->msg = emalloc (strlen (fmsg->msg) + 1);
strcpy (rmsg->msg, fmsg->msg);
rmsg->msg = strdup (fmsg->msg);
rmsg->failctx = rmsg->lastctx;
} else {
/* Skip subsequent failure messages, only happens for CK_NOFORK */
}
free (fmsg->msg);
} else if (type == CK_MSG_DURATION) {
DurationMsg *cmsg = (DurationMsg *) & msg;
rmsg->duration = cmsg->duration;
} else
check_type (type, __FILE__, __LINE__);
@ -375,10 +409,11 @@ rcvmsg_create (void)
{
RcvMsg *rmsg;
rmsg = emalloc (sizeof (RcvMsg));
rmsg = (RcvMsg *) emalloc (sizeof (RcvMsg));
rmsg->lastctx = CK_CTX_INVALID;
rmsg->failctx = CK_CTX_INVALID;
rmsg->msg = NULL;
rmsg->duration = -1;
reset_rcv_test (rmsg);
reset_rcv_fixture (rmsg);
return rmsg;
@ -406,40 +441,47 @@ rcvmsg_update_ctx (RcvMsg * rmsg, enum ck_result_ctx ctx)
static void
rcvmsg_update_loc (RcvMsg * rmsg, const char *file, int line)
{
int flen = strlen (file);
if (rmsg->lastctx == CK_CTX_TEST) {
free (rmsg->test_file);
rmsg->test_line = line;
rmsg->test_file = emalloc (flen + 1);
strcpy (rmsg->test_file, file);
rmsg->test_file = strdup (file);
} else {
free (rmsg->fixture_file);
rmsg->fixture_line = line;
rmsg->fixture_file = emalloc (flen + 1);
strcpy (rmsg->fixture_file, file);
rmsg->fixture_file = strdup (file);
}
}
RcvMsg *
punpack (int fdes)
punpack (FILE * fdes)
{
int nread, n;
int nread, nparse, n;
char *buf;
char *obuf;
RcvMsg *rmsg;
nread = read_buf (fdes, &buf);
obuf = buf;
rmsg = rcvmsg_create ();
while (nread > 0) {
/* Allcate a buffer */
buf = (char *) emalloc (CK_MAX_MSG_SIZE);
/* Fill the buffer from the file */
nread = read_buf (fdes, CK_MAX_MSG_SIZE, buf);
nparse = nread;
/* While not all parsed */
while (nparse > 0) {
/* Parse one message */
n = get_result (buf, rmsg);
nread -= n;
buf += n;
nparse -= n;
/* Move remaining data in buffer to the beginning */
memmove (buf, buf + n, nparse);
/* If EOF has not been seen */
if (nread > 0) {
/* Read more data into empty space at end of the buffer */
nread = read_buf (fdes, n, buf + nparse);
nparse += nread;
}
}
free (buf);
free (obuf);
if (rmsg->lastctx == CK_CTX_INVALID) {
free (rmsg);
rmsg = NULL;

View file

@ -22,10 +22,12 @@
#define CHECK_PACK_H
enum ck_msg_type {
enum ck_msg_type
{
CK_MSG_CTX,
CK_MSG_FAIL,
CK_MSG_LOC,
CK_MSG_DURATION,
CK_MSG_LAST
};
@ -45,11 +47,17 @@ typedef struct FailMsg
char *msg;
} FailMsg;
typedef struct DurationMsg
{
int duration;
} DurationMsg;
typedef union
{
CtxMsg ctx_msg;
FailMsg fail_msg;
LocMsg loc_msg;
DurationMsg duration_msg;
} CheckMsg;
typedef struct RcvMsg
@ -61,6 +69,7 @@ typedef struct RcvMsg
char *test_file;
int test_line;
char *msg;
int duration;
} RcvMsg;
void rcvmsg_free (RcvMsg * rmsg);
@ -69,8 +78,7 @@ void rcvmsg_free (RcvMsg *rmsg);
int pack (enum ck_msg_type type, char **buf, CheckMsg * msg);
int upack (char *buf, CheckMsg * msg, enum ck_msg_type *type);
void ppack (int fdes, enum ck_msg_type type, CheckMsg *msg);
RcvMsg *punpack (int fdes);
void ppack (FILE * fdes, enum ck_msg_type type, CheckMsg * msg);
RcvMsg *punpack (FILE * fdes);
#endif /*CHECK_PACK_H */

View file

@ -18,7 +18,7 @@
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "../lib/libcompat.h"
#include <stdio.h>
#include <string.h>
@ -83,30 +83,16 @@ srunner_fprint_results (FILE * file, SRunner * sr, enum print_output print_mode)
resultlst = sr->resultlst;
for (list_front (resultlst); !list_at_end (resultlst);
list_advance (resultlst)) {
TestResult *tr = list_val (resultlst);
for (check_list_front (resultlst); !check_list_at_end (resultlst);
check_list_advance (resultlst)) {
TestResult *tr = (TestResult *) check_list_val (resultlst);
tr_fprint (file, tr, print_mode);
}
return;
}
void
tr_fprint (FILE * file, TestResult * tr, enum print_output print_mode)
{
if (print_mode == CK_ENV) {
print_mode = get_env_printmode ();
}
if ((print_mode >= CK_VERBOSE && tr->rtype == CK_PASS) ||
(tr->rtype != CK_PASS && print_mode >= CK_NORMAL)) {
char *trstr = tr_str (tr);
fprintf (file, "%s\n", trstr);
free (trstr);
}
}
static void
fprint_xml_esc (FILE * file, const char *str)
{
for (; *str != '\0'; str++) {
@ -138,24 +124,40 @@ fprint_xml_esc (FILE * file, const char *str)
}
}
void
tr_fprint (FILE * file, TestResult * tr, enum print_output print_mode)
{
if (print_mode == CK_ENV) {
print_mode = get_env_printmode ();
}
if ((print_mode >= CK_VERBOSE && tr->rtype == CK_PASS) ||
(tr->rtype != CK_PASS && print_mode >= CK_NORMAL)) {
char *trstr = tr_str (tr);
fprintf (file, "%s\n", trstr);
free (trstr);
}
}
void
tr_xmlprint (FILE * file, TestResult * tr,
enum print_output print_mode CK_ATTRIBUTE_UNUSED)
{
char result[10];
char *path_name;
char *file_name;
char *slash;
char *path_name = NULL;
char *file_name = NULL;
char *slash = NULL;
switch (tr->rtype) {
case CK_PASS:
strcpy (result, "success");
snprintf (result, sizeof (result), "%s", "success");
break;
case CK_FAILURE:
strcpy (result, "failure");
snprintf (result, sizeof (result), "%s", "failure");
break;
case CK_ERROR:
strcpy (result, "error");
snprintf (result, sizeof (result), "%s", "error");
break;
case CK_TEST_RESULT_INVALID:
default:
@ -163,22 +165,33 @@ tr_xmlprint (FILE * file, TestResult * tr,
break;
}
if (tr->file) {
slash = strrchr (tr->file, '/');
if (slash == NULL) {
path_name = (char *) ".";
slash = strrchr (tr->file, '\\');
}
if (slash == NULL) {
path_name = strdup (".");
file_name = tr->file;
} else {
path_name = strdup (tr->file);
path_name[slash - tr->file] = 0; /* Terminate the temporary string. */
file_name = slash + 1;
}
}
fprintf (file, " <test result=\"%s\">\n", result);
fprintf (file, " <path>%s</path>\n", path_name);
fprintf (file, " <fn>%s:%d</fn>\n", file_name, tr->line);
fprintf (file, " <path>%s</path>\n",
(path_name == NULL ? "" : path_name));
fprintf (file, " <fn>%s:%d</fn>\n",
(file_name == NULL ? "" : file_name), tr->line);
fprintf (file, " <id>%s</id>\n", tr->tname);
fprintf (file, " <iteration>%d</iteration>\n", tr->iter);
fprintf (file, " <duration>%d.%06d</duration>\n",
tr->duration < 0 ? -1 : tr->duration / US_PER_SEC,
tr->duration < 0 ? 0 : tr->duration % US_PER_SEC);
fprintf (file, " <description>");
fprint_xml_esc (file, tr->tcname);
fprintf (file, "</description>\n");
@ -187,15 +200,14 @@ tr_xmlprint (FILE * file, TestResult * tr,
fprintf (file, "</message>\n");
fprintf (file, " </test>\n");
if (slash != NULL) {
free (path_name);
}
}
enum print_output
get_env_printmode (void)
{
char *env = getenv ("CK_VERBOSITY");
if (env == NULL)
return CK_NORMAL;
if (strcmp (env, "silent") == 0)

View file

@ -21,6 +21,8 @@
#ifndef CHECK_PRINT_H
#define CHECK_PRINT_H
/* escape XML special characters (" ' < > &) in str and print to file */
void fprint_xml_esc (FILE * file, const char *str);
void tr_fprint (FILE * file, TestResult * tr, enum print_output print_mode);
void tr_xmlprint (FILE * file, TestResult * tr, enum print_output print_mode);
void srunner_fprint (FILE * file, SRunner * sr, enum print_output print_mode);

View file

@ -18,20 +18,16 @@
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "../lib/libcompat.h"
#include <sys/types.h>
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <signal.h>
#include <setjmp.h>
#include "check.h"
#include "check_error.h"
@ -56,35 +52,40 @@ enum tf_type
CK_NOFORK_FIXTURE
};
/* all functions are defined in the same order they are declared.
functions that depend on forking are gathered all together.
non-static functions are at the end of the file. */
static void srunner_run_init (SRunner * sr, enum print_output print_mode);
static void srunner_run_end (SRunner * sr, enum print_output print_mode);
static void srunner_iterate_suites (SRunner * sr, enum print_output print_mode);
static void srunner_iterate_suites (SRunner * sr,
const char *sname, const char *tcname, enum print_output print_mode);
static void srunner_iterate_tcase_tfuns (SRunner * sr, TCase * tc);
static void srunner_add_failure (SRunner * sr, TestResult * tf);
static TestResult *srunner_run_setup (List * func_list,
enum fork_status fork_usage, const char *test_name, const char *setup_name);
static int srunner_run_unchecked_setup (SRunner * sr, TCase * tc);
static TestResult *tcase_run_checked_setup (SRunner * sr, TCase * tc);
static void srunner_run_teardown (List * l);
static void srunner_run_unchecked_teardown (TCase * tc);
static void srunner_run_teardown (List * fixture_list,
enum fork_status fork_usage);
static void srunner_run_unchecked_teardown (SRunner * sr, TCase * tc);
static void tcase_run_checked_teardown (TCase * tc);
static void srunner_run_tcase (SRunner * sr, TCase * tc);
static TestResult *tcase_run_tfun_nofork (SRunner * sr, TCase * tc, TF * tf,
int i);
static TestResult *receive_result_info_nofork (const char *tcname,
const char *tname, int iter);
const char *tname, int iter, int duration);
static void set_nofork_info (TestResult * tr);
static char *pass_msg (void);
#ifdef _POSIX_VERSION
#if defined(HAVE_FORK) && HAVE_FORK==1
static TestResult *tcase_run_tfun_fork (SRunner * sr, TCase * tc, TF * tf,
int i);
static TestResult *receive_result_info_fork (const char *tcname,
const char *tname, int iter, int status, int expected_signal,
unsigned char allowed_exit_value);
const char *tname, int iter,
int status, int expected_signal, signed char allowed_exit_value);
static void set_fork_info (TestResult * tr, int status, int expected_signal,
unsigned char allowed_exit_value);
signed char allowed_exit_value);
static char *signal_msg (int sig);
static char *signal_error_msg (int signal_received, int signal_expected);
static char *exit_msg (int exitstatus);
@ -106,7 +107,7 @@ sig_handler (int sig_nr)
break;
}
}
#endif /* _POSIX_VERSION */
#endif /* HAVE_FORK */
#define MSG_LEN 100
@ -130,6 +131,7 @@ srunner_run_end (SRunner * sr, enum print_output CK_ATTRIBUTE_UNUSED print_mode)
static void
srunner_iterate_suites (SRunner * sr,
const char *sname, const char *tcname,
enum print_output CK_ATTRIBUTE_UNUSED print_mode)
{
List *slst;
@ -138,15 +140,26 @@ srunner_iterate_suites (SRunner * sr,
slst = sr->slst;
for (list_front (slst); !list_at_end (slst); list_advance (slst)) {
Suite *s = list_val (slst);
for (check_list_front (slst); !check_list_at_end (slst);
check_list_advance (slst)) {
Suite *s = (Suite *) check_list_val (slst);
if (((sname != NULL) && (strcmp (sname, s->name) != 0))
|| ((tcname != NULL) && (!suite_tcase (s, tcname))))
continue;
log_suite_start (sr, s);
tcl = s->tclst;
for (list_front (tcl); !list_at_end (tcl); list_advance (tcl)) {
tc = list_val (tcl);
for (check_list_front (tcl); !check_list_at_end (tcl);
check_list_advance (tcl)) {
tc = (TCase *) check_list_val (tcl);
if ((tcname != NULL) && (strcmp (tcname, tc->name) != 0)) {
continue;
}
srunner_run_tcase (sr, tc);
}
@ -163,36 +176,42 @@ srunner_iterate_tcase_tfuns (SRunner * sr, TCase * tc)
tfl = tc->tflst;
for (list_front (tfl); !list_at_end (tfl); list_advance (tfl)) {
for (check_list_front (tfl); !check_list_at_end (tfl);
check_list_advance (tfl)) {
int i;
tfun = list_val (tfl);
tfun = (TF *) check_list_val (tfl);
for (i = tfun->loop_start; i < tfun->loop_end; i++) {
log_test_start (sr, tc, tfun);
switch (srunner_fork_status (sr)) {
case CK_FORK:
#ifdef _POSIX_VERSION
#if defined(HAVE_FORK) && HAVE_FORK==1
tr = tcase_run_tfun_fork (sr, tc, tfun, i);
#else /* _POSIX_VERSION */
#else /* HAVE_FORK */
eprintf ("This version does not support fork", __FILE__, __LINE__);
#endif /* _POSIX_VERSION */
#endif /* HAVE_FORK */
break;
case CK_NOFORK:
tr = tcase_run_tfun_nofork (sr, tc, tfun, i);
break;
case CK_FORK_GETENV:
default:
eprintf ("Bad fork status in SRunner", __FILE__, __LINE__);
}
if (NULL != tr) {
srunner_add_failure (sr, tr);
log_test_end (sr, tr);
}
}
}
}
static void
srunner_add_failure (SRunner * sr, TestResult * tr)
{
list_add_end (sr->resultlst, tr);
check_list_add_end (sr->resultlst, tr);
sr->stats->n_checked++; /* count checks during setup, test, and teardown */
if (tr->rtype == CK_FAILURE)
sr->stats->n_failed++;
@ -201,62 +220,30 @@ srunner_add_failure (SRunner * sr, TestResult * tr)
}
static int
srunner_run_unchecked_setup (SRunner * sr, TCase * tc)
{
TestResult *tr;
List *l;
Fixture *f;
int rval = 1;
set_fork_status (CK_NOFORK);
l = tc->unch_sflst;
for (list_front (l); !list_at_end (l); list_advance (l)) {
send_ctx_info (CK_CTX_SETUP);
f = list_val (l);
f->fun ();
tr = receive_result_info_nofork (tc->name, "unchecked_setup", 0);
if (tr->rtype != CK_PASS) {
srunner_add_failure (sr, tr);
rval = 0;
break;
}
free (tr->file);
free (tr->msg);
free (tr);
}
set_fork_status (srunner_fork_status (sr));
return rval;
}
static TestResult *
tcase_run_checked_setup (SRunner * sr, TCase * tc)
srunner_run_setup (List * fixture_list, enum fork_status fork_usage,
const char *test_name, const char *setup_name)
{
TestResult *tr = NULL;
List *l;
Fixture *f;
enum fork_status fstat = srunner_fork_status (sr);
Fixture *setup_fixture;
l = tc->ch_sflst;
if (fstat == CK_FORK) {
if (fork_usage == CK_FORK) {
send_ctx_info (CK_CTX_SETUP);
}
for (list_front (l); !list_at_end (l); list_advance (l)) {
if (fstat == CK_NOFORK) {
send_ctx_info (CK_CTX_SETUP);
}
f = list_val (l);
f->fun ();
for (check_list_front (fixture_list); !check_list_at_end (fixture_list);
check_list_advance (fixture_list)) {
setup_fixture = (Fixture *) check_list_val (fixture_list);
/* Stop the setup and return the failure if nofork mode. */
if (fstat == CK_NOFORK) {
tr = receive_result_info_nofork (tc->name, "checked_setup", 0);
if (fork_usage == CK_NOFORK) {
send_ctx_info (CK_CTX_SETUP);
if (0 == setjmp (error_jmp_buffer)) {
setup_fixture->fun ();
}
/* Stop the setup and return the failure in nofork mode. */
tr = receive_result_info_nofork (test_name, setup_name, 0, -1);
if (tr->rtype != CK_PASS) {
break;
}
@ -265,34 +252,75 @@ tcase_run_checked_setup (SRunner * sr, TCase * tc)
free (tr->msg);
free (tr);
tr = NULL;
} else {
setup_fixture->fun ();
}
}
return tr;
}
static void
srunner_run_teardown (List * l)
static int
srunner_run_unchecked_setup (SRunner * sr, TCase * tc)
{
Fixture *f;
TestResult *tr = NULL;
int rval = 1;
for (list_front (l); !list_at_end (l); list_advance (l)) {
f = list_val (l);
set_fork_status (CK_NOFORK);
tr = srunner_run_setup (tc->unch_sflst, CK_NOFORK, tc->name,
"unchecked_setup");
set_fork_status (srunner_fork_status (sr));
if (tr != NULL && tr->rtype != CK_PASS) {
srunner_add_failure (sr, tr);
rval = 0;
}
return rval;
}
static TestResult *
tcase_run_checked_setup (SRunner * sr, TCase * tc)
{
TestResult *tr = srunner_run_setup (tc->ch_sflst, srunner_fork_status (sr),
tc->name, "checked_setup");
return tr;
}
static void
srunner_run_teardown (List * fixture_list, enum fork_status fork_usage)
{
Fixture *fixture;
for (check_list_front (fixture_list); !check_list_at_end (fixture_list);
check_list_advance (fixture_list)) {
fixture = (Fixture *) check_list_val (fixture_list);
send_ctx_info (CK_CTX_TEARDOWN);
f->fun ();
if (fork_usage == CK_NOFORK) {
if (0 == setjmp (error_jmp_buffer)) {
fixture->fun ();
} else {
/* Abort the remaining teardowns */
break;
}
} else {
fixture->fun ();
}
}
}
static void
srunner_run_unchecked_teardown (TCase * tc)
srunner_run_unchecked_teardown (SRunner * sr, TCase * tc)
{
srunner_run_teardown (tc->unch_tflst);
srunner_run_teardown (tc->unch_tflst, srunner_fork_status (sr));
}
static void
tcase_run_checked_teardown (TCase * tc)
{
srunner_run_teardown (tc->ch_tflst);
srunner_run_teardown (tc->ch_tflst, CK_NOFORK);
}
static void
@ -300,7 +328,7 @@ srunner_run_tcase (SRunner * sr, TCase * tc)
{
if (srunner_run_unchecked_setup (sr, tc)) {
srunner_iterate_tcase_tfuns (sr, tc);
srunner_run_unchecked_teardown (tc);
srunner_run_unchecked_teardown (sr, tc);
}
}
@ -308,29 +336,40 @@ static TestResult *
tcase_run_tfun_nofork (SRunner * sr, TCase * tc, TF * tfun, int i)
{
TestResult *tr;
struct timespec ts_start = { 0, 0 }, ts_end = {
0, 0};
tr = tcase_run_checked_setup (sr, tc);
if (tr == NULL) {
clock_gettime (check_get_clockid (), &ts_start);
if (0 == setjmp (error_jmp_buffer)) {
tfun->fn (i);
}
clock_gettime (check_get_clockid (), &ts_end);
tcase_run_checked_teardown (tc);
return receive_result_info_nofork (tc->name, tfun->name, i);
return receive_result_info_nofork (tc->name, tfun->name, i,
DIFF_IN_USEC (ts_start, ts_end));
}
return tr;
}
static TestResult *
receive_result_info_nofork (const char *tcname, const char *tname, int iter)
receive_result_info_nofork (const char *tcname,
const char *tname, int iter, int duration)
{
TestResult *tr;
tr = receive_test_result (0);
if (tr == NULL)
if (tr == NULL) {
eprintf ("Failed to receive test result", __FILE__, __LINE__);
} else {
tr->tcname = tcname;
tr->tname = tname;
tr->iter = iter;
tr->duration = duration;
set_nofork_info (tr);
}
return tr;
}
@ -349,18 +388,23 @@ set_nofork_info (TestResult * tr)
static char *
pass_msg (void)
{
char *msg = emalloc (sizeof ("Passed"));
strcpy (msg, "Passed");
return msg;
return strdup ("Passed");
}
#ifdef _POSIX_VERSION
#if defined(HAVE_FORK) && HAVE_FORK==1
static TestResult *
tcase_run_tfun_fork (SRunner * sr, TCase * tc, TF * tfun, int i)
{
pid_t pid_w;
pid_t pid;
int status = 0;
struct timespec ts_start = { 0, 0 }, ts_end = {
0, 0};
timer_t timerid;
struct itimerspec timer_spec;
TestResult *tr;
pid = fork ();
if (pid == -1)
@ -368,19 +412,41 @@ tcase_run_tfun_fork (SRunner * sr, TCase * tc, TF * tfun, int i)
if (pid == 0) {
setpgid (0, 0);
group_pid = getpgrp ();
tcase_run_checked_setup (sr, tc);
tr = tcase_run_checked_setup (sr, tc);
free (tr);
clock_gettime (check_get_clockid (), &ts_start);
tfun->fn (i);
clock_gettime (check_get_clockid (), &ts_end);
tcase_run_checked_teardown (tc);
send_duration_info (DIFF_IN_USEC (ts_start, ts_end));
exit (EXIT_SUCCESS);
} else {
group_pid = pid;
}
alarm_received = 0;
alarm (tc->timeout);
if (timer_create (check_get_clockid (),
NULL /* fire SIGALRM if timer expires */ ,
&timerid) == 0) {
/* Set the timer to fire once */
timer_spec.it_value = tc->timeout;
timer_spec.it_interval.tv_sec = 0;
timer_spec.it_interval.tv_nsec = 0;
if (timer_settime (timerid, 0, &timer_spec, NULL) == 0) {
do {
pid_w = waitpid (pid, &status, 0);
} while (pid_w == -1);
}
while (pid_w == -1);
} else {
eprintf ("Error in call to timer_settime:", __FILE__, __LINE__);
}
/* If the timer has not fired, disable it */
timer_delete (timerid);
} else {
eprintf ("Error in call to timer_create:", __FILE__, __LINE__);
}
killpg (pid, SIGKILL); /* Kill remaining processes. */
@ -391,28 +457,30 @@ tcase_run_tfun_fork (SRunner * sr, TCase * tc, TF * tfun, int i)
static TestResult *
receive_result_info_fork (const char *tcname,
const char *tname,
int iter, int status, int expected_signal, unsigned char allowed_exit_value)
int iter, int status, int expected_signal, signed char allowed_exit_value)
{
TestResult *tr;
tr = receive_test_result (waserror (status, expected_signal));
if (tr == NULL)
if (tr == NULL) {
eprintf ("Failed to receive test result", __FILE__, __LINE__);
} else {
tr->tcname = tcname;
tr->tname = tname;
tr->iter = iter;
set_fork_info (tr, status, expected_signal, allowed_exit_value);
}
return tr;
}
static void
set_fork_info (TestResult * tr, int status, int signal_expected,
unsigned char allowed_exit_value)
signed char allowed_exit_value)
{
int was_sig = WIFSIGNALED (status);
int was_exit = WIFEXITED (status);
int exit_status = WEXITSTATUS (status);
signed char exit_status = WEXITSTATUS (status);
int signal_received = WTERMSIG (status);
if (was_sig) {
@ -420,23 +488,38 @@ set_fork_info (TestResult * tr, int status, int signal_expected,
if (alarm_received) {
/* Got alarm instead of signal */
tr->rtype = CK_ERROR;
if (tr->msg != NULL) {
free (tr->msg);
}
tr->msg = signal_error_msg (signal_received, signal_expected);
} else {
tr->rtype = CK_PASS;
if (tr->msg != NULL) {
free (tr->msg);
}
tr->msg = pass_msg ();
}
} else if (signal_expected != 0) {
/* signal received, but not the expected one */
tr->rtype = CK_ERROR;
if (tr->msg != NULL) {
free (tr->msg);
}
tr->msg = signal_error_msg (signal_received, signal_expected);
} else {
/* signal received and none expected */
tr->rtype = CK_ERROR;
if (tr->msg != NULL) {
free (tr->msg);
}
tr->msg = signal_msg (signal_received);
}
} else if (signal_expected == 0) {
if (was_exit && exit_status == allowed_exit_value) {
tr->rtype = CK_PASS;
if (tr->msg != NULL) {
free (tr->msg);
}
tr->msg = pass_msg ();
} else if (was_exit && exit_status != allowed_exit_value) {
if (tr->msg == NULL) { /* early exit */
@ -448,19 +531,24 @@ set_fork_info (TestResult * tr, int status, int signal_expected,
}
} else { /* a signal was expected and none raised */
if (was_exit) {
if (tr->msg != NULL) {
free (tr->msg);
}
tr->msg = exit_msg (exit_status);
if (exit_status == allowed_exit_value)
if (exit_status == allowed_exit_value) {
tr->rtype = CK_FAILURE; /* normal exit status */
else
} else {
tr->rtype = CK_FAILURE; /* early exit */
}
}
}
}
static char *
signal_msg (int signal)
{
char *msg = emalloc (MSG_LEN); /* free'd by caller */
char *msg = (char *) emalloc (MSG_LEN); /* free'd by caller */
if (alarm_received) {
snprintf (msg, MSG_LEN, "Test timeout expired");
} else {
@ -475,11 +563,13 @@ signal_error_msg (int signal_received, int signal_expected)
{
char *sig_r_str;
char *sig_e_str;
char *msg = emalloc (MSG_LEN); /* free'd by caller */
char *msg = (char *) emalloc (MSG_LEN); /* free'd by caller */
sig_r_str = strdup (strsignal (signal_received));
sig_e_str = strdup (strsignal (signal_expected));
if (alarm_received) {
snprintf (msg, MSG_LEN, "Test timeout expired, expected signal %d (%s)",
snprintf (msg, MSG_LEN,
"Test timeout expired, expected signal %d (%s)",
signal_expected, sig_e_str);
} else {
snprintf (msg, MSG_LEN, "Received signal %d (%s), expected %d (%s)",
@ -493,7 +583,8 @@ signal_error_msg (int signal_received, int signal_expected)
static char *
exit_msg (int exitval)
{
char *msg = emalloc (MSG_LEN); /* free'd by caller */
char *msg = (char *) emalloc (MSG_LEN); /* free'd by caller */
snprintf (msg, MSG_LEN, "Early exit with return value %d", exitval);
return msg;
}
@ -509,24 +600,29 @@ waserror (int status, int signal_expected)
return ((was_sig && (signal_received != signal_expected)) ||
(was_exit && exit_status != 0));
}
#endif /* _POSIX_VERSION */
#endif /* HAVE_FORK */
enum fork_status
srunner_fork_status (SRunner * sr)
{
if (sr->fstat == CK_FORK_GETENV) {
char *env = getenv ("CK_FORK");
if (env == NULL)
#if defined(HAVE_FORK) && HAVE_FORK==1
return CK_FORK;
#else
return CK_NOFORK;
#endif
if (strcmp (env, "no") == 0)
return CK_NOFORK;
else {
#ifdef _POSIX_VERSION
#if defined(HAVE_FORK) && HAVE_FORK==1
return CK_FORK;
#else /* _POSIX_VERSION */
#else /* HAVE_FORK */
eprintf ("This version does not support fork", __FILE__, __LINE__);
return CK_NOFORK;
#endif /* _POSIX_VERSION */
#endif /* HAVE_FORK */
}
} else
return sr->fstat;
@ -535,16 +631,38 @@ srunner_fork_status (SRunner * sr)
void
srunner_set_fork_status (SRunner * sr, enum fork_status fstat)
{
#if !defined(HAVE_FORK) || HAVE_FORK==0
/* If fork() is unavailable, do not allow a fork mode to be set */
if (fstat != CK_NOFORK) {
eprintf ("This version does not support fork", __FILE__, __LINE__);
}
#endif /* ! HAVE_FORK */
sr->fstat = fstat;
}
void
srunner_run_all (SRunner * sr, enum print_output print_mode)
{
#ifdef _POSIX_VERSION
srunner_run (sr, NULL, /* All test suites. */
NULL, /* All test cases. */
print_mode);
}
void
srunner_run (SRunner * sr, const char *sname, const char *tcname,
enum print_output print_mode)
{
#if defined(HAVE_SIGACTION) && defined(HAVE_FORK)
struct sigaction old_action;
struct sigaction new_action;
#endif /* _POSIX_VERSION */
#endif /* HAVE_SIGACTION && HAVE_FORK */
/* Get the selected test suite and test case from the
environment. */
if (!tcname)
tcname = getenv ("CK_RUN_CASE");
if (!sname)
sname = getenv ("CK_RUN_SUITE");
if (sr == NULL)
return;
@ -552,50 +670,54 @@ srunner_run_all (SRunner * sr, enum print_output print_mode)
eprintf ("Bad print_mode argument to srunner_run_all: %d",
__FILE__, __LINE__, print_mode);
}
#ifdef _POSIX_VERSION
#if defined(HAVE_SIGACTION) && defined(HAVE_FORK)
memset (&new_action, 0, sizeof new_action);
new_action.sa_handler = sig_handler;
sigaction (SIGALRM, &new_action, &old_action);
#endif /* _POSIX_VERSION */
#endif /* HAVE_SIGACTION && HAVE_FORK */
srunner_run_init (sr, print_mode);
srunner_iterate_suites (sr, print_mode);
srunner_iterate_suites (sr, sname, tcname, print_mode);
srunner_run_end (sr, print_mode);
#ifdef _POSIX_VERSION
#if defined(HAVE_SIGACTION) && defined(HAVE_FORK)
sigaction (SIGALRM, &old_action, NULL);
#endif /* _POSIX_VERSION */
#endif /* HAVE_SIGACTION && HAVE_FORK */
}
pid_t
check_fork (void)
{
#ifdef _POSIX_VERSION
#if defined(HAVE_FORK) && HAVE_FORK==1
pid_t pid = fork ();
/* Set the process to a process group to be able to kill it easily. */
if (pid >= 0) {
setpgid (pid, group_pid);
}
return pid;
#else /* _POSIX_VERSION */
#else /* HAVE_FORK */
eprintf ("This version does not support fork", __FILE__, __LINE__);
return 0;
#endif /* _POSIX_VERSION */
#endif /* HAVE_FORK */
}
void
check_waitpid_and_exit (pid_t pid CK_ATTRIBUTE_UNUSED)
{
#ifdef _POSIX_VERSION
#if defined(HAVE_FORK) && HAVE_FORK==1
pid_t pid_w;
int status;
if (pid > 0) {
do {
pid_w = waitpid (pid, &status, 0);
} while (pid_w == -1);
}
while (pid_w == -1);
if (waserror (status, 0)) {
exit (EXIT_FAILURE);
}
}
exit (EXIT_SUCCESS);
#else /* _POSIX_VERSION */
#else /* HAVE_FORK */
eprintf ("This version does not support fork", __FILE__, __LINE__);
#endif /* _POSIX_VERSION */
#endif /* HAVE_FORK */
}

View file

@ -18,7 +18,7 @@
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "../lib/libcompat.h"
#include <stdio.h>
#include <stdarg.h>
@ -79,11 +79,12 @@ char *
ck_strdup_printf (const char *fmt, ...)
{
/* Guess we need no more than 100 bytes. */
int n, size = 100;
int n;
size_t size = 100;
char *p;
va_list ap;
p = emalloc (size);
p = (char *) emalloc (size);
while (1) {
/* Try to print in the allocated space. */
@ -91,16 +92,16 @@ ck_strdup_printf (const char *fmt, ...)
n = vsnprintf (p, size, fmt, ap);
va_end (ap);
/* If that worked, return the string. */
if (n > -1 && n < size)
if (n > -1 && n < (int) size)
return p;
/* Else try again with more space. */
if (n > -1) /* C99 conform vsnprintf() */
size = n + 1; /* precisely what is needed */
size = (size_t) n + 1; /* precisely what is needed */
else /* glibc 2.0 */
size *= 2; /* twice the old size */
p = erealloc (p, size);
p = (char *) erealloc (p, size);
}
}
@ -108,6 +109,7 @@ static const char *
tr_type_str (TestResult * tr)
{
const char *str = NULL;
if (tr->ctx == CK_CTX_TEST) {
if (tr->rtype == CK_PASS)
str = "P";

View file

@ -0,0 +1,65 @@
#include "libcompat.h"
#ifdef __MACH__
#include <mach/clock.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <CoreServices/CoreServices.h>
#include <unistd.h>
#endif
#define NANOSECONDS_PER_SECOND 1000000000
int
clock_gettime (clockid_t clk_id CK_ATTRIBUTE_UNUSED, struct timespec *ts)
{
#ifdef __MACH__
/* OS X does not have clock_gettime, use mach_absolute_time */
static mach_timebase_info_data_t sTimebaseInfo;
uint64_t rawTime;
uint64_t nanos;
rawTime = mach_absolute_time ();
/*
* OS X has a function to convert abs time to nano seconds: AbsoluteToNanoseconds
* However, the function may not be available as we may not have
* access to CoreServices. Because of this, we convert the abs time
* to nano seconds manually.
*/
/*
* First grab the time base used on the system, if this is the first
* time we are being called. We can check if the value is uninitialized,
* as the denominator will be zero.
*/
if (sTimebaseInfo.denom == 0) {
(void) mach_timebase_info (&sTimebaseInfo);
}
/*
* Do the conversion. We hope that the multiplication doesn't
* overflow; the price you pay for working in fixed point.
*/
nanos = rawTime * sTimebaseInfo.numer / sTimebaseInfo.denom;
/*
* Fill in the timespec container
*/
ts->tv_sec = nanos / NANOSECONDS_PER_SECOND;
ts->tv_nsec = nanos - (ts->tv_sec * NANOSECONDS_PER_SECOND);
#else
/*
* As there is no function to fall back onto to get the current
* time, zero out the time so the caller will have a sane value.
*/
ts->tv_sec = 0;
ts->tv_nsec = 0;
#endif
return 0;
}

View file

@ -0,0 +1,15 @@
#include "libcompat.h"
/* silence warnings about an empty library */
void
ck_do_nothing (void)
{
assert (0);
/*
* to silence warning about this function actually
* returning, but being marked as noreturn. assert()
* must be marked as a function that returns.
*/
exit (1);
}

View file

@ -0,0 +1,213 @@
#ifndef LIBCOMPAT_H
#define LIBCOMPAT_H
#if HAVE_CONFIG_H
#include <config.h>
#endif
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
#define GCC_VERSION_AT_LEAST(major, minor) \
((__GNUC__ > (major)) || \
(__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))
#else
#define GCC_VERSION_AT_LEAST(major, minor) 0
#endif
#if GCC_VERSION_AT_LEAST(2,95)
#define CK_ATTRIBUTE_UNUSED __attribute__ ((unused))
#else
#define CK_ATTRIBUTE_UNUSED
#endif /* GCC 2.95 */
#if GCC_VERSION_AT_LEAST(2,5)
#define CK_ATTRIBUTE_NORETURN __attribute__ ((noreturn))
#else
#define CK_ATTRIBUTE_NORETURN
#endif /* GCC 2.5 */
/*
* Used for MSVC to create the export attribute
* CK_DLL_EXP is defined during the compilation of the library
* on the command line.
*/
#ifndef CK_DLL_EXP
#define CK_DLL_EXP
#endif
#if _MSC_VER
#include <WinSock2.h> /* struct timeval, API used in gettimeofday implementation */
#include <io.h> /* read, write */
#include <process.h> /* getpid */
#endif /* _MSC_VER */
/* defines size_t */
#include <sys/types.h>
/* provides assert */
#include <assert.h>
/* defines FILE */
#include <stdio.h>
/* defines exit() */
#include <stdlib.h>
/* provides localtime and struct tm */
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif /* !HAVE_SYS_TIME_H */
#include <time.h>
/* declares fork(), _POSIX_VERSION. according to Autoconf.info,
unistd.h defines _POSIX_VERSION if the system is POSIX-compliant,
so we will use this as a test for all things uniquely provided by
POSIX like sigaction() and fork() */
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
/* declares pthread_create and friends */
#ifdef HAVE_PTHREAD
#include <pthread.h>
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
/* replacement functions for broken originals */
#if !HAVE_DECL_ALARM
CK_DLL_EXP unsigned int alarm (unsigned int seconds);
#endif /* !HAVE_DECL_ALARM */
#if !HAVE_MALLOC
CK_DLL_EXP void *rpl_malloc (size_t n);
#endif /* !HAVE_MALLOC */
#if !HAVE_REALLOC
CK_DLL_EXP void *rpl_realloc (void *p, size_t n);
#endif /* !HAVE_REALLOC */
#if !HAVE_GETPID && HAVE__GETPID
#define getpid _getpid
#endif /* !HAVE_GETPID && HAVE__GETPID */
#if !HAVE_GETTIMEOFDAY
CK_DLL_EXP int gettimeofday (struct timeval *tv, void *tz);
#endif /* !HAVE_GETTIMEOFDAY */
#if !HAVE_DECL_LOCALTIME_R
#if !defined(localtime_r)
CK_DLL_EXP struct tm *localtime_r (const time_t * clock, struct tm *result);
#endif
#endif /* !HAVE_DECL_LOCALTIME_R */
#if !HAVE_DECL_STRDUP && !HAVE__STRDUP
CK_DLL_EXP char *strdup (const char *str);
#elif !HAVE_DECL_STRDUP && HAVE__STRDUP
#define strdup _strdup
#endif /* !HAVE_DECL_STRDUP && HAVE__STRDUP */
#if !HAVE_DECL_STRSIGNAL
CK_DLL_EXP const char *strsignal (int sig);
#endif /* !HAVE_DECL_STRSIGNAL */
/*
* On systems where clock_gettime() is not available, or
* on systems where some clocks may not be supported, the
* definition for CLOCK_MONOTONIC and CLOCK_REALTIME may not
* be available. These should define which type of clock
* clock_gettime() should use. We define it here if it is
* not defined simply so the reimplementation can ignore it.
*
* We set the values of these clocks to some (hopefully)
* invalid value, to avoid the case where we define a
* clock with a valid value, and unintentionally use
* an actual good clock by accident.
*/
#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC -1
#endif
#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME -1
#endif
#ifndef HAVE_LIBRT
#ifdef STRUCT_TIMESPEC_DEFINITION_MISSING
/*
* The following structure is defined in POSIX 1003.1 for times
* specified in seconds and nanoseconds. If it is not defined in
* time.g, then we need to define it here
*/
struct timespec
{
time_t tv_sec;
long tv_nsec;
};
#endif /* STRUCT_TIMESPEC_DEFINITION_MISSING */
#ifdef STRUCT_ITIMERSPEC_DEFINITION_MISSING
/*
* The following structure is defined in POSIX.1b for timer start values and intervals.
* If it is not defined in time.h, then we need to define it here.
*/
struct itimerspec
{
struct timespec it_interval;
struct timespec it_value;
};
#endif /* STRUCT_ITIMERSPEC_DEFINITION_MISSING */
/*
* Do a simple forward declaration in case the struct is not defined.
* In the versions of timer_create in libcompat, sigevent is never
* used.
*/
struct sigevent;
CK_DLL_EXP int clock_gettime (clockid_t clk_id, struct timespec *ts);
CK_DLL_EXP int timer_create (clockid_t clockid, struct sigevent *sevp,
timer_t * timerid);
CK_DLL_EXP int timer_settime (timer_t timerid, int flags,
const struct itimerspec *new_value, struct itimerspec *old_value);
CK_DLL_EXP int timer_delete (timer_t timerid);
#endif /* HAVE_LIBRT */
/*
* The following checks are to determine if the system's
* snprintf (or its variants) should be replaced with
* the C99 compliant version in libcompat.
*/
#if HAVE_CONFIG_H
#include <config.h>
#endif
#if HAVE_STDARG_H
#include <stdarg.h>
#if !HAVE_VSNPRINTF
CK_DLL_EXP int rpl_vsnprintf (char *, size_t, const char *, va_list);
#define vsnprintf rpl_vsnprintf
#endif
#if !HAVE_SNPRINTF
CK_DLL_EXP int rpl_snprintf (char *, size_t, const char *, ...);
#define snprintf rpl_snprintf
#endif
#endif /* HAVE_STDARG_H */
#if !HAVE_GETLINE
CK_DLL_EXP ssize_t getline (char **lineptr, size_t * n, FILE * stream);
#endif
/* silence warnings about an empty library */
CK_DLL_EXP void
ck_do_nothing (void)
CK_ATTRIBUTE_NORETURN;
#endif /* !LIBCOMPAT_H */

View file

@ -0,0 +1,19 @@
#include "libcompat.h"
#if !defined(localtime_r)
struct tm *
localtime_r (const time_t * clock, struct tm *result)
{
struct tm *now = localtime (clock);
if (now == NULL) {
return NULL;
} else {
*result = *now;
}
return result;
}
#endif /* !defined(localtime_r) */

View file

@ -0,0 +1,10 @@
#include "libcompat.h"
const char *
strsignal (int sig)
{
static char signame[40];
sprintf (signame, "SIG #%d", sig);
return signame;
}

View file

@ -0,0 +1,15 @@
#include "libcompat.h"
int
timer_create (clockid_t clockid CK_ATTRIBUTE_UNUSED,
struct sigevent *sevp CK_ATTRIBUTE_UNUSED,
timer_t * timerid CK_ATTRIBUTE_UNUSED)
{
/*
* The create function does nothing. timer_settime will use
* alarm to set the timer, and timer_delete will stop the
* alarm
*/
return 0;
}

View file

@ -0,0 +1,33 @@
#include "libcompat.h"
int
timer_delete (timer_t timerid CK_ATTRIBUTE_UNUSED)
{
#ifdef HAVE_SETITIMER
/*
* If the system does not have timer_settime() but does have
* setitimer() use that instead of alarm().
*/
struct itimerval interval;
/*
* Setting values to '0' results in disabling the running timer.
*/
interval.it_value.tv_sec = 0;
interval.it_value.tv_usec = 0;
interval.it_interval.tv_sec = 0;
interval.it_interval.tv_usec = 0;
return setitimer (ITIMER_REAL, &interval, NULL);
#else
/*
* There is only one timer, that used by alarm.
* Setting alarm(0) will not set a new alarm, and
* will kill the previous timer.
*/
alarm (0);
return 0;
#endif
}

View file

@ -0,0 +1,37 @@
#include "libcompat.h"
int
timer_settime (timer_t timerid CK_ATTRIBUTE_UNUSED,
int flags CK_ATTRIBUTE_UNUSED,
const struct itimerspec *new_value,
struct itimerspec *old_value CK_ATTRIBUTE_UNUSED)
{
#ifdef HAVE_SETITIMER
/*
* If the system does not have timer_settime() but does have
* setitimer() use that instead of alarm().
*/
struct itimerval interval;
interval.it_value.tv_sec = new_value->it_value.tv_sec;
interval.it_value.tv_usec = new_value->it_value.tv_nsec / 1000;
interval.it_interval.tv_sec = new_value->it_interval.tv_sec;
interval.it_interval.tv_usec = new_value->it_interval.tv_nsec / 1000;
return setitimer (ITIMER_REAL, &interval, NULL);
#else
int seconds = new_value->it_value.tv_sec;
/*
* As the alarm() call has only second precision, if the caller
* specifies partial seconds, we round up to the nearest second.
*/
if (new_value->it_value.tv_nsec > 0) {
seconds += 1;
}
alarm (seconds);
return 0;
#endif
}