While reading the doc in libev I find some C code of which the syntax is quite weird.
static void
stdin_cb (EV_P_ ev_io *w, int revents)
{
puts ("stdin ready");
// for one-shot events, one must manually stop the watcher
// with its corresponding stop function.
ev_io_stop (EV_A_ w);
// this causes all nested ev_run's to stop iterating
ev_break (EV_A_ EVBREAK_ALL);
}
I'm not sure what the EV_P_ is here, could anyone help explain it to me?
I have tried to google the syntax of method signature in C but no good matches.
See ev.h:
#if EV_MULTIPLICITY
struct ev_loop;
# define EV_P struct ev_loop *loop /* a loop as sole parameter in a declaration */
# define EV_P_ EV_P, /* a loop as first of multiple parameters */
...
#else
# define EV_P void
# define EV_P_
...
#endif
Therefore the line
stdin_cb (EV_P_ ev_io *w, int revents)
expands to
stdin_cb (struct ev_loop *loop, ev_io *w, int revents)
or
stdin_cb (ev_io *w, int revents)
depending on the value of EV_MULTIPLICITY
As pointed out by #Shawn, there is a Macro magic section that explains it:
EV_P, EV_P_
This provides the loop parameter for functions, if one is required ("ev loop parameter"). The EV_P form is used when this is the sole parameter, EV_P_ is used when other parameters are following. Example:
// this is how ev_unref is being declared
static void ev_unref (EV_P);
// this is how you can declare your typical callback
static void cb (EV_P_ ev_timer *w, int revents)
It declares a parameter loop of type struct ev_loop *, quite suitable for use with EV_A.
EV_P_ is a macro which means "an ev loop as a parameter, plus a comma".
EV_A_ is a macro which means "an ev loop as an argument, plus a comma".
They are defined as
#define EV_P struct ev_loop *loop /* a loop as sole parameter in a declaration */
#define EV_P_ EV_P, /* a loop as first of multiple parameters */
#define EV_A loop /* a loop as sole argument to a function call */
#define EV_A_ EV_A, /* a loop as first of multiple arguments */
or as
# define EV_P void
# define EV_P_
# define EV_A
# define EV_A_
(Some whitespace was removed so it would fit better.)
This means
static void stdin_cb( EV_P_ ev_io *w, int revents ) {
puts( "stdin ready" );
ev_io_stop( EV_A_ w );
ev_break( EV_A_ EVBREAK_ALL );
}
is equivalent to
static void stdin_cb( struct ev_loop *loop, ev_io *w, int revents ) {
puts( "stdin ready" );
ev_io_stop( loop, w );
ev_break( loop, EVBREAK_ALL );
}
or
static void stdin_cb( ev_io *w, int revents ) {
puts( "stdin ready" );
ev_io_stop( w );
ev_break( EVBREAK_ALL );
}
Which set of #define directives is used is configurable.
If EV_MULTIPLICITY is set and nonzero, the first set is used. The first set allows multiple ev loops to be used in the same program. (Perhaps in different threads.)
If EV_MULTIPLICITY is unset or zero, the second set is used. The second is more efficient since it uses global variables instead of passing a structure to every ev-related function. But the program can only have one event loop.
Related
I've a huge C project with a module reading and managing configuration data. If I have to add a new configuration parameter, I'll have to edit several functions, e.g. as pseudo-code:
void read_configuration(config *c) {
read_param("p1", c->p1);
read_param("p2", c->p2);
read_param("p3", c->p3);
/* ... */
}
void dump_configuration(config *c) {
dump_param("p1", c->p1);
dump_param("p2", c->p2);
dump_param("p3", c->p3);
/* ... */
}
Is there a way to ensure by macro at compile time, that each location has at least the same count of parameters? I thought of making dump_param some kind of macro counting the invocations and then add something like
#if nr_read != nr_dump
#error "You forgot something, idiot!"
#endif
at the end of the module. I can't find a method to make the macro count its invocations, though...
Since the list of parameters is the same in both functions, how about factoring that out and avoid any possible mismatch ?
Using X-macros
#define X_CONFIG_PARAMS(config) \
X("p1", (config).p1) \
X("p2", (config).p2) \
X("p3", (config).p3)
void read_configuration(config *c) {
#define X(name, param) read_param(name, ¶m);
X_CONFIG_PARAMS(*c)
#undef X
}
void dump_configuration(config *c) {
#define X(name, param) dump_param(name, ¶m);
X_CONFIG_PARAMS(*c)
#undef X
}
Using function pointers
void alter_config(config *c, void(*func)(char const *name, Param *param)) {
func("p1", &c->p1);
func("p2", &c->p2);
func("p3", &c->p3);
}
void read_configuration(config *c) {
alter_config(c, read_param);
}
void dump_configuration(config *c) {
alter_config(c, dump_param);
}
Using an array and offsetof
struct param_info {
char const *name;
size_t config_offs;
};
param_info allParams[] = {
{"p1", offsetof(config, p1)},
{"p2", offsetof(config, p2)},
{"p3", offsetof(config, p3)}
};
void read_configuration(config *c) {
size_t paramCount = sizeof allParams / sizeof *allParams;
for(size_t i = 0; i < paramCount; ++i) {
Param *p = (Param*)((char*)config + allParams[i].config_offs);
read_param(allParams[i].name, p);
}
}
void dump_configuration(config *c) {
size_t paramCount = sizeof allParams / sizeof *allParams;
for(size_t i = 0; i < paramCount; ++i) {
Param *p = (Param*)((char*)config + allParams[i].config_offs);
dump_param(allParams[i].name, p);
}
}
I would rather let the preprocessor write the code in the first place.
It could look something like this:
Define the list of parameters in a separate file, say parameters.inc:
PARAM (p1)
PARAM (p2)
...
Then in the source code locally define the macro PARAM as required and let the preprocessor include and expand the contents of parameters.inc:
void read_configuration(config *c) {
#define PARAM(NAME) read_param(#NAME, c->NAME);
#include "parameters.inc"
#undef PARAM
}
void dump_configuration(config *c) {
#define PARAM(NAME) dump_param(#NAME, c->NAME);
#include "parameters.inc"
#undef PARAM
}
I don't think you can do this at compile time without ugly hacks.
What you could do: add a test to your test suite which replaces the header that contains the read_param() and dump_param() macros so they generate code which only updates a counter. Then, in the main() function of that test, place an assertion that compares both counters and fails if they're not equal.
You do have a test suite and run it at compile time, right? ;-)
However, I do agree with the comment that it's probably better to do this differently. In an approach called "table-driven programming", you turn the macro definition and data definition on their head (that is, you have the #define in your .c file and the use of the macro in the header rather than the other way around), you don't have this problem. Poul-Henning Kamp, of FreeBSD fame, explains very well how to that here.
Suppose I have a function like this:
static int init_processing(char *buf, FILE *stream, enum operationMode mode) {
/* save index of `stream' in current operations */
/* start processing */
/* save some important variables for continue_processing */
off_t position;
enum operationMode _mode;
return num_processing_operations_left;
}
.. that I would be calling occasionally. And I have another function that does the actual processing I want:
static int continue_processing(FILE *stream) {
/* lookup the index of `stream' in current operations */
/* do some stuff */
/* save some static variables */
static off_t left = position;
static void *some_ptr;
return --num_processing_operations_left;
}
I also have a cleaning function to invoke when finishing up a certain operation:
static int end_processing(FILE *stream) {
/* check */
if (num_processing_operations_left)
return 1;
/* clean everything */
return 0;
}
As you can see, this related functions technique is very familiar that it is used by the standard library itself (e.g [malloc, free, realloc], [fdopen, fopen, fclose]).
What I want to achieve here, is how to share some variables across a bunch of functions ?
I thought of two solutions:
Put each set of functions in a file of their own, providing static variables valid only for the file itself.
Use only one function that takes an extra enum parameter as a mode and structure the function accordingly.
But these solutions aren't actually solutions, they're just workarounds to cope with the problem. So, is there any standard technique to share variables among functions ?
Create a context structure keeping all you need:
struct Context
{
FILE * stream;
off_t position;
unsigned num_processing_operations_left;
/* define some more important variables */
}
and pass it to all functions in question:
static int init_processing(struct Context * pctx, char *buf, enum operationMode mode);
static int continue_processing(struct Context * pctx);
static int end_processing(struct Context * pctx);
int main(void)
{
struct Context ctx = {0};
/* init ctx here */
int result = init_processing(&ctx, ...);
...
result = continue_processing(&ctx);
...
result = end_processing(&ctx);
...
}
It seems sensible to wrap a call to del_timer() or del_timer_sync() within an if() statement, such as:
if (timer_pending(&t))
{
del_timer_sync(&t);
}
but can I safely do that in the case where we may not yet have done our init_timer() call on struct t? Do I need to jump through hoops doing something like this instead?
init_timer(&t);
t.function = foo;
.
.
.
if (t.function && timer_pending(&t)) ...
I doubt it.
Here's the code (timer.h#L169) for timer_pending:
static inline int timer_pending(const struct timer_list * timer) {
return timer->entry.next != NULL;
}
And here's the code (timer.c#L621) that ends up initializing the timer when you call init_timer:
static void do_init_timer(struct timer_list *timer, unsigned int flags,
const char *name, struct lock_class_key *key)
{
struct tvec_base *base = __raw_get_cpu_var(tvec_bases);
timer->entry.next = NULL;
timer->base = (void *)((unsigned long)base | flags);
timer->slack = -1;
#ifdef CONFIG_TIMER_STATS
timer->start_site = NULL;
timer->start_pid = -1;
memset(timer->start_comm, 0, TASK_COMM_LEN);
#endif
lockdep_init_map(&timer->lockdep_map, name, key, 0);
}
Note that timer_pending is checking entry.next which is not initialized until you call init_timer. So timer_pending may return true when the timer has not been initialized.
I don't know what the effect may be of callingn del_timer_sync on a timer which has not been initialized, though.
del_timer() does the timer_pending() check internally, you don't have to.
You must however have called init_timer() before calling del_timer. (After all, if you don't it'll just contain garbage).
So this is enough:
init_timer(&t);
del_timer(&t);
for the following libevent API:
void event_set(struct event *ev, int fd, short event, void (*cb)(int, short, void *), void *arg)
event_add(struct event *ev, const struct timeval *timeout);
struct event* event_new (struct event_base *, evutil_socket_t, short, event_callback_fn, void)
I want to know:
1) for pointer parameter ev in the second function event_add, the function event_add makes a local copy of the ev structure or not?
for example, if I do something like:
code snippet 1:
struct event ev;
event_set(&ev, ..para list 1...); // event 1
event_add(&ev, ...);
event_set(&ev, ..para list 2...); // event 2
event_add(&ev, ...);
event 1 is different from event 2 because parameter list 1 is different from parameter list 2. if event_add makes a local copy, then it is no problem, but if event_add doesn't make a local copy, then these two event_add actually add only event 2?
besides, if I have a main function:
void func(){
struct event ev;
event_set(&ev, ...);
event_add(&ev, ...)
}
int main(){
func();
event_base_dispatch(base);
}
after func() is called, the execution returns to main(). since ev is a local variable inside func(). if event_add(&ev,...) doesn't make a local copy, then ev is nowhere to find and there will be a problem.
so can I call event_add() on a local event structure?
I want to add many timer events(use something like evtimer_set) from time to time, and the adding happens in some callback functions. so I can't define global variabbles for the timeout events in advance, if event_add() can't be called on local variables, are there any solutions for this?
2) event_new returns a structure pointer, I want to know where is the structure, it is in a stack/heap memory or static memory?
MY special case::
in the main.c
int main(){
struct event_base *base;
struct event pcap_ev;
..... // here I get a file descriptor pcapfd
event_set(&pcap_ev, pcapfd, EV_READ|EV_PERSIST, on_capture, pcap_handle);
event_base_set(base, &pcap_ev);
event_add(&pcap_ev, NULL);
.....
event_base_dispatch(base);
}
on_capture callback function:
void *on_capture(int pcapfd, short op, void *arg)
{
pcap_t *handle;
handle = (pcap_t *)arg;
fqueue_t* pkt_queue;
pkt_queue = init_fqueue();
pcap_dispatch(handle, -1, collect_pkt, pkt_queue); // this function put all the cached packets into pkt_queue
process_pcap(pkt_queue);
}
the sub-routine process_pcap():
void process_pcap(pkt_queue);{
for (pkt in pkt_queue){ // here is pseudo code
insert(table, pkt); // here insert the pkt into a certain table
struct event pkt_ev;
evtimer_set(&pkt_ev, timer_cb, NULL); // I want to call timer_cb after timeout
event_base_set(base, &pkt_ev);
event_add(&pkt_ev, timeout);
}
}
the callback function timer_cb():
timer_cb(...){
if(...) delete(table, pkt);
.......
}
I'm just afraid timer_cb() won't be called because pkt_ev is a local variable.
You must use a different struct event instance for each event you want to know about. You can only call event_add() on a local struct event variable if that variable has a lifetime that spans across all calls to the event loop API up until it is removed with event_del().
The allocation functions default to the heap, but you can substitute your own allocation routines in its place with event_set_mem_functions().
Rookie question FYI.
Whenever I compile/run the code, extern tolayer2(rtpktTo1); I receive a warning.
The warning reads, as in the title, Warning: parameter names (without types) in function declaration
Any help appreciated.
node0.c
extern struct rtpkt {
int sourceid; /* id of sending router sending this pkt */
int destid; /* id of router to which pkt being sent
(must be an immediate neighbor) */
int mincost[4]; /* current understanding of min cost to node 0 ... 3 */
};
/* Create routing packets (rtpkt) and send to neighbors via tolayer2(). */
struct rtpkt rtpktTo1;
rtpktTo1.sourceid = 0;
rtpktTo1.destid = 1;
rtpktTo1.mincost[0] = minCost[0];
rtpktTo1.mincost[1] = minCost[1];
rtpktTo1.mincost[2] = minCost[2];
rtpktTo1.mincost[3] = minCost[3];
extern tolayer2(rtpktTo1);
prog3.c
tolayer2(packet)
struct rtpkt packet;
{
/* This has a lot of code in it */
}
The assignments to rkpktTo1.* are not apparently in a function or declaration, unless this is a code fragment. Wrap them in a function. The warning is a bit misleading.
The declaration of tolayer2() should have a return type as well as a parameter type. Since there isn't one, int is assumed. This may not be what is intended, but it should compile without warnings and errors:
node0.c
struct rtpkt {
int sourceid; /* id of sending router sending this pkt */
int destid; /* id of router to which pkt being sent
(must be an immediate neighbor) */
int mincost[4]; /* current understanding of min cost to node 0 ... 3 */
};
/* Create routing packets (rtpkt) and send to neighbors via tolayer2(). */
void function () {
struct rtpkt rtpktTo1;
rtpktTo1.sourceid = 0;
rtpktTo1.destid = 1;
rtpktTo1.mincost[0] = minCost[0];
rtpktTo1.mincost[1] = minCost[1];
rtpktTo1.mincost[2] = minCost[2];
rtpktTo1.mincost[3] = minCost[3];
}
extern void tolayer2(struct rtpkt *rtpktTo1);
prog3.c
void
tolayer2(struct rtpkt *packet)
{
/* This has a lot of code in it */
}
Passing a structure by value is often not appropriate, so I have changed it to pass by reference.
In prog3.c
tolayer2(packet)
struct rtpkt packet;
{ /* ... */ }
This is old syntax (very old: before ANSI standardized C in 1989), but perfectly legal in C89 and C99. Don't use it though: prefer
int tolayer2(struct rtpkt packet)
{ /* ... */ }
In the declaration extern tolayer2(rtpktTo1);, rtpktTo1 is a parameter name (like the error says), while you should give a type there:
extern tolayer2(struct rtpkt);
or
extern tolayer2(struct rtpkt *);
or
extern tolayer2(struct rtpkt const *);
or similar, since that is what the compiler needs to know about your function before compiling client code. The parameter name is useless to the compiler at this point and therefore optional.
(And really, you should add a return type as well, and note that extern has no meaning in your struct definition.)