3 * Timeout extension for test vector framework
5 * (c) 2024 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of the mLib utilities library.
12 * mLib is free software: you can redistribute it and/or modify it under
13 * the terms of the GNU Library General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or (at
15 * your option) any later version.
17 * mLib is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
20 * License for more details.
22 * You should have received a copy of the GNU Library General Public
23 * License along with mLib. If not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
28 /*----- Header files ------------------------------------------------------*/
35 #include <sys/types.h>
39 #include "tvec-timeout.h"
40 #include "tvec-types.h"
42 /*----- Main code ---------------------------------------------------------*/
44 static void reset(struct tvec_timeoutctx
*tc
)
46 const struct tvec_timeoutenv
*te
= tc
->te
;
48 tc
->timer
= te
->timer
; tc
->t
= te
->t
; tc
->f
&= ~TVTF_SETMASK
;
51 /* --- @tvec_timeoutsetup@ --- *
53 * Arguments: @struct tvec_state *tv@ = test vector state
54 * @const struct tvec_env *env@ = environment description
55 * @void *pctx@ = parent context (ignored)
56 * @void *ctx@ = context pointer to initialize
60 * Use: Initialize a timeout environment context.
62 * The environment description should be a @struct
66 void tvec_timeoutsetup(struct tvec_state
*tv
, const struct tvec_env
*env
,
67 void *pctx
, void *ctx
)
69 struct tvec_timeoutctx
*tc
= ctx
;
70 const struct tvec_timeoutenv
*te
= (struct tvec_timeoutenv
*)env
;
71 const struct tvec_env
*subenv
= te
->env
;
77 if (subenv
&& subenv
->ctxsz
) tc
->subctx
= x_alloc(tv
->a
, subenv
->ctxsz
);
79 if (subenv
&& subenv
->setup
) subenv
->setup(tv
, subenv
, tc
, tc
->subctx
);
82 /* --- @tvec_timeoutfindvar@, @setvar@ --- *
84 * Arguments: @struct tvec_state *tv@ = test vector state
85 * @const char *var@ = variable name to set
86 * @const union tvec_regval *rv@ = register value
87 * @void **ctx_out@ = where to put the @setvar@ context
88 * @void *ctx@ = context pointer
90 * Returns: @tvec_timeoutfindvar@ returns a pointer to the variable
91 * definition, or null; @setvar@ returns zero on success or
94 * Use: Find a definition for a special variable. The following
95 * special variables are supported.
97 * * %|@timeout|% is the duration to wait before killing the
100 * * %|@timer|% is the timer to use to measure the duration.
102 * Unrecognized variables are passed to the subordinate
103 * environment, if there is one.
106 static int setvar(struct tvec_state
*tv
, const char *var
,
107 const union tvec_regval
*rv
, void *ctx
)
109 struct tvec_timeoutctx
*tc
= ctx
;
111 if (STRCMP(var
, ==, "@timeout")) {
112 if (tc
->f
&TVTF_SETTMO
) return (tvec_dupregerr(tv
, var
));
113 tc
->t
= rv
->f
; tc
->f
|= TVTF_SETTMO
;
114 } else if (STRCMP(var
, ==, "@timer")) {
115 if (tc
->f
&TVTF_SETTMR
) return (tvec_dupregerr(tv
, var
));
116 tc
->timer
= rv
->i
; tc
->f
|= TVTF_SETTMR
;
117 } else assert(!"unknown var");
121 static const struct tvec_vardef timeout_var
=
122 { sizeof(struct tvec_reg
), setvar
,
123 { "@timeout", &tvty_duration
, -1, 0 } };
125 static const struct tvec_iassoc timer_assocs
[] = {
126 { "REAL", ITIMER_REAL
},
127 { "VIRTUAL", ITIMER_VIRTUAL
},
128 { "PROF", ITIMER_PROF
},
131 static const struct tvec_ienuminfo timer_enum
=
132 { "interval-timer", timer_assocs
, &tvrange_int
};
133 static const struct tvec_vardef timer_var
=
134 { sizeof(struct tvec_reg
), setvar
,
135 { "@timer", &tvty_ienum
, -1, 0, { &timer_enum
} } };
137 const struct tvec_vardef
*tvec_timeoutfindvar
138 (struct tvec_state
*tv
, const char *var
, void **ctx_out
, void *ctx
)
140 struct tvec_timeoutctx
*tc
= ctx
;
141 const struct tvec_timeoutenv
*te
= tc
->te
;
142 const struct tvec_env
*subenv
= te
->env
;
144 if (STRCMP(var
, ==, "@timeout")) { *ctx_out
= tc
; return (&timeout_var
); }
145 else if (STRCMP(var
, ==, "@timer")) { *ctx_out
= tc
; return (&timer_var
); }
146 else if (subenv
&& subenv
->findvar
)
147 return (subenv
->findvar(tv
, var
, ctx_out
, tc
->subctx
));
151 /* --- @tvec_timeoutbefore@ --- *
153 * Arguments: @struct tvec_state *tv@ = test vector state
154 * @void *ctx@ = context pointer
158 * Use: Invoke the subordinate environment's @before@ function to
159 * prepare for the test.
162 void tvec_timeoutbefore(struct tvec_state
*tv
, void *ctx
)
164 struct tvec_timeoutctx
*tc
= ctx
;
165 const struct tvec_timeoutenv
*te
= tc
->te
;
166 const struct tvec_env
*subenv
= te
->env
;
168 if (subenv
&& subenv
->before
) subenv
->before(tv
, tc
->subctx
);
171 /* --- @tvec_timeoutrun@ --- *
173 * Arguments: @struct tvec_state *tv@ = test vector state
174 * @tvec_testfn *fn@ = test function to run
175 * @void *ctx@ = context pointer for the test function
179 * Use: Runs a test with a timeout attached.
182 void tvec_timeoutrun(struct tvec_state
*tv
, tvec_testfn
*fn
, void *ctx
)
184 struct tvec_timeoutctx
*tc
= ctx
;
185 const struct tvec_timeoutenv
*te
= tc
->te
;
186 const struct tvec_env
*subenv
= te
->env
;
187 struct itimerval itv
;
189 itv
.it_interval
.tv_sec
= 0; itv
.it_interval
.tv_usec
= 0;
190 itv
.it_value
.tv_sec
= tc
->t
;
191 itv
.it_value
.tv_usec
= (tc
->t
- itv
.it_value
.tv_sec
)*1e6
;
193 if (setitimer(tc
->timer
, &itv
, 0))
194 tvec_skip(tv
, "failed to set interval timer: %s", strerror(errno
));
196 if (subenv
&& subenv
->run
) subenv
->run(tv
, fn
, tc
->subctx
);
197 else { fn(tv
->in
, tv
->out
, tc
->subctx
); tvec_check(tv
, 0); }
199 itv
.it_interval
.tv_sec
= 0; itv
.it_interval
.tv_usec
= 0;
200 itv
.it_value
.tv_sec
= 0; itv
.it_value
.tv_usec
= 0;
201 if (setitimer(tc
->timer
, &itv
, 0))
202 tvec_error(tv
, "failed to disarm interval timer: %s", strerror(errno
));
206 /* --- @tvec_timeoutafter@ --- *
208 * Arguments: @struct tvec_state *tv@ = test vector state
209 * @void *ctx@ = context pointer
213 * Use: Invoke the subordinate environment's @after@ function to
214 * clean up after the test.
217 void tvec_timeoutafter(struct tvec_state
*tv
, void *ctx
)
219 struct tvec_timeoutctx
*tc
= ctx
;
220 const struct tvec_timeoutenv
*te
= tc
->te
;
221 const struct tvec_env
*subenv
= te
->env
;
223 /* Reset variables. */
226 /* Pass the call on to the subsidiary environment. */
227 if (subenv
&& subenv
->after
) subenv
->after(tv
, tc
->subctx
);
230 /* --- @tvec_timeoutteardown@ --- *
232 * Arguments: @struct tvec_state *tv@ = test vector state
233 * @void *ctx@ = context pointer
237 * Use: Tear down the timeoutmark environment.
240 void tvec_timeoutteardown(struct tvec_state
*tv
, void *ctx
)
242 struct tvec_timeoutctx
*tc
= ctx
;
243 const struct tvec_timeoutenv
*te
= tc
->te
;
244 const struct tvec_env
*subenv
= te
->env
;
246 /* Just call the subsidiary environment. */
247 if (subenv
&& subenv
->teardown
) subenv
->teardown(tv
, tc
->subctx
);
248 x_free(tv
->a
, tc
->subctx
);
251 /*----- That's all, folks -------------------------------------------------*/