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>
40 /*----- Main code ---------------------------------------------------------*/
42 static void reset(struct tvec_timeoutctx
*tc
)
44 const struct tvec_timeoutenv
*te
= tc
->te
;
46 tc
->timer
= te
->timer
; tc
->t
= te
->t
; tc
->f
&= ~TVTF_SETMASK
;
49 /* --- @tvec_timeoutsetup@ --- *
51 * Arguments: @struct tvec_state *tv@ = test vector state
52 * @const struct tvec_env *env@ = environment description
53 * @void *pctx@ = parent context (ignored)
54 * @void *ctx@ = context pointer to initialize
58 * Use: Initialize a timeout environment context.
60 * The environment description should be a @struct
64 void tvec_timeoutsetup(struct tvec_state
*tv
, const struct tvec_env
*env
,
65 void *pctx
, void *ctx
)
67 struct tvec_timeoutctx
*tc
= ctx
;
68 const struct tvec_timeoutenv
*te
= (struct tvec_timeoutenv
*)env
;
69 const struct tvec_env
*subenv
= te
->env
;
76 if (subenv
&& subenv
->ctxsz
) tc
->subctx
= xmalloc(subenv
->ctxsz
);
77 if (subenv
&& subenv
->setup
) subenv
->setup(tv
, subenv
, tc
, tc
->subctx
);
80 /* --- @tvec_timeoutfindvar@, @setvar@ --- *
82 * Arguments: @struct tvec_state *tv@ = test vector state
83 * @const char *var@ = variable name to set
84 * @const union tvec_regval *rv@ = register value
85 * @void **ctx_out@ = where to put the @setvar@ context
86 * @void *ctx@ = context pointer
88 * Returns: @tvec_timeoutfindvar@ returns a pointer to the variable
89 * definition, or null; @setvar@ returns zero on success or
92 * Use: Find a definition for a special variable. The following
93 * special variables are supported.
95 * * %|@timeout|% is the duration to wait before killing the
98 * * %|@timer|% is the timer to use to measure the duration.
100 * Unrecognized variables are passed to the subordinate
101 * environment, if there is one.
104 static int setvar(struct tvec_state
*tv
, const char *var
,
105 const union tvec_regval
*rv
, void *ctx
)
107 struct tvec_timeoutctx
*tc
= ctx
;
109 if (STRCMP(var
, ==, "@timeout")) {
110 if (tc
->f
&TVTF_SETTMO
) return (tvec_dupregerr(tv
, var
));
111 tc
->t
= rv
->f
; tc
->f
|= TVTF_SETTMO
;
112 } else if (STRCMP(var
, ==, "@timer")) {
113 if (tc
->f
&TVTF_SETTMR
) return (tvec_dupregerr(tv
, var
));
114 tc
->timer
= rv
->i
; tc
->f
|= TVTF_SETTMR
;
115 } else assert(!"unknown var");
119 static const struct tvec_vardef timeout_var
=
120 { sizeof(struct tvec_reg
), setvar
,
121 { "@timeout", &tvty_duration
, -1, 0 } };
123 static const struct tvec_iassoc timer_assocs
[] = {
124 { "REAL", ITIMER_REAL
},
125 { "VIRTUAL", ITIMER_VIRTUAL
},
126 { "PROF", ITIMER_PROF
},
129 static const struct tvec_ienuminfo timer_enum
=
130 { "interval-timer", timer_assocs
, &tvrange_int
};
131 static const struct tvec_vardef timer_var
=
132 { sizeof(struct tvec_reg
), setvar
,
133 { "@timer", &tvty_ienum
, -1, 0, { &timer_enum
} } };
135 const struct tvec_vardef
*tvec_timeoutfindvar
136 (struct tvec_state
*tv
, const char *var
, void **ctx_out
, void *ctx
)
138 struct tvec_timeoutctx
*tc
= ctx
;
139 const struct tvec_timeoutenv
*te
= tc
->te
;
140 const struct tvec_env
*subenv
= te
->env
;
142 if (STRCMP(var
, ==, "@timeout")) { *ctx_out
= tc
; return (&timeout_var
); }
143 else if (STRCMP(var
, ==, "@timer")) { *ctx_out
= tc
; return (&timer_var
); }
144 else if (subenv
&& subenv
->findvar
)
145 return (subenv
->findvar(tv
, var
, ctx_out
, tc
->subctx
));
149 /* --- @tvec_timeoutbefore@ --- *
151 * Arguments: @struct tvec_state *tv@ = test vector state
152 * @void *ctx@ = context pointer
156 * Use: Invoke the subordinate environment's @before@ function to
157 * prepare for the test.
160 void tvec_timeoutbefore(struct tvec_state
*tv
, void *ctx
)
162 struct tvec_timeoutctx
*tc
= ctx
;
163 const struct tvec_timeoutenv
*te
= tc
->te
;
164 const struct tvec_env
*subenv
= te
->env
;
166 if (subenv
&& subenv
->before
) subenv
->before(tv
, tc
->subctx
);
169 /* --- @tvec_timeoutrun@ --- *
171 * Arguments: @struct tvec_state *tv@ = test vector state
172 * @tvec_testfn *fn@ = test function to run
173 * @void *ctx@ = context pointer for the test function
177 * Use: Runs a test with a timeout attached.
180 void tvec_timeoutrun(struct tvec_state
*tv
, tvec_testfn
*fn
, void *ctx
)
182 struct tvec_timeoutctx
*tc
= ctx
;
183 const struct tvec_timeoutenv
*te
= tc
->te
;
184 const struct tvec_env
*subenv
= te
->env
;
185 struct itimerval itv
;
187 itv
.it_interval
.tv_sec
= 0; itv
.it_interval
.tv_usec
= 0;
188 itv
.it_value
.tv_sec
= tc
->t
;
189 itv
.it_value
.tv_usec
= (tc
->t
- itv
.it_value
.tv_sec
)*1e6
;
191 if (setitimer(tc
->timer
, &itv
, 0))
192 tvec_skip(tv
, "failed to set interval timer: %s", strerror(errno
));
194 if (subenv
&& subenv
->run
) subenv
->run(tv
, fn
, tc
->subctx
);
195 else { fn(tv
->in
, tv
->out
, tc
->subctx
); tvec_check(tv
, 0); }
197 itv
.it_interval
.tv_sec
= 0; itv
.it_interval
.tv_usec
= 0;
198 itv
.it_value
.tv_sec
= 0; itv
.it_value
.tv_usec
= 0;
199 if (setitimer(tc
->timer
, &itv
, 0))
200 tvec_error(tv
, "failed to disarm interval timer: %s", strerror(errno
));
204 /* --- @tvec_timeoutafter@ --- *
206 * Arguments: @struct tvec_state *tv@ = test vector state
207 * @void *ctx@ = context pointer
211 * Use: Invoke the subordinate environment's @after@ function to
212 * clean up after the test.
215 void tvec_timeoutafter(struct tvec_state
*tv
, void *ctx
)
217 struct tvec_timeoutctx
*tc
= ctx
;
218 const struct tvec_timeoutenv
*te
= tc
->te
;
219 const struct tvec_env
*subenv
= te
->env
;
221 /* Reset variables. */
224 /* Pass the call on to the subsidiary environment. */
225 if (subenv
&& subenv
->after
) subenv
->after(tv
, tc
->subctx
);
228 /* --- @tvec_timeoutteardown@ --- *
230 * Arguments: @struct tvec_state *tv@ = test vector state
231 * @void *ctx@ = context pointer
235 * Use: Tear down the timeoutmark environment.
238 void tvec_timeoutteardown(struct tvec_state
*tv
, void *ctx
)
240 struct tvec_timeoutctx
*tc
= ctx
;
241 const struct tvec_timeoutenv
*te
= tc
->te
;
242 const struct tvec_env
*subenv
= te
->env
;
244 /* Just call the subsidiary environment. */
245 if (subenv
&& subenv
->teardown
) subenv
->teardown(tv
, tc
->subctx
);
248 /*----- That's all, folks -------------------------------------------------*/