Documented sockets, events and timers.
This commit is contained in:
parent
10304bed43
commit
525fa2c1f0
5 changed files with 196 additions and 14 deletions
2
lib/Doc
2
lib/Doc
|
@ -6,5 +6,5 @@ D resource.sgml
|
||||||
S resource.c
|
S resource.c
|
||||||
S mempool.c
|
S mempool.c
|
||||||
S slab.c
|
S slab.c
|
||||||
S socket.h
|
|
||||||
S event.c
|
S event.c
|
||||||
|
S ../sysdep/unix/io.c
|
||||||
|
|
54
lib/event.c
54
lib/event.c
|
@ -6,6 +6,21 @@
|
||||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DOC: Events
|
||||||
|
*
|
||||||
|
* Events are there to keep track of deferred execution.
|
||||||
|
* Since BIRD is single-threaded, it requires long lasting tasks to be split to smaller
|
||||||
|
* parts, so that no module can monopolize the CPU. To split such a task, just create
|
||||||
|
* an &event resource, point it to the function you want to have called and call ev_schedule()
|
||||||
|
* to ask the core to run the event when nothing more important will require attention.
|
||||||
|
*
|
||||||
|
* You can also define your own event lists (the &event_list structure), enqueue your
|
||||||
|
* events in them and explicitly ask to run them.
|
||||||
|
*
|
||||||
|
* The actual implementation is system dependent.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "nest/bird.h"
|
#include "nest/bird.h"
|
||||||
#include "lib/event.h"
|
#include "lib/event.h"
|
||||||
|
|
||||||
|
@ -39,6 +54,13 @@ static struct resclass ev_class = {
|
||||||
ev_dump
|
ev_dump
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ev_new - create a new event
|
||||||
|
* @p: resource pool
|
||||||
|
*
|
||||||
|
* This function creates a new event resource. To use it,
|
||||||
|
* you need to fill the structure fields and call ev_schedule().
|
||||||
|
*/
|
||||||
event *
|
event *
|
||||||
ev_new(pool *p)
|
ev_new(pool *p)
|
||||||
{
|
{
|
||||||
|
@ -50,6 +72,16 @@ ev_new(pool *p)
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ev_run - run an event
|
||||||
|
* @e: an event
|
||||||
|
*
|
||||||
|
* This function explicitly runs the event @e (calls its hook
|
||||||
|
* function) and removes it from an event list if it's linked to any.
|
||||||
|
*
|
||||||
|
* From the hook function, you can call ev_enqueue() or ev_schedule()
|
||||||
|
* to re-add the event.
|
||||||
|
*/
|
||||||
inline void
|
inline void
|
||||||
ev_run(event *e)
|
ev_run(event *e)
|
||||||
{
|
{
|
||||||
|
@ -57,6 +89,14 @@ ev_run(event *e)
|
||||||
e->hook(e->data);
|
e->hook(e->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ev_enqueue - enqueue an event
|
||||||
|
* @l: an event list
|
||||||
|
* @e: an event
|
||||||
|
*
|
||||||
|
* ev_enqueue() stores the event @e to the specified event
|
||||||
|
* list @l which can be run by calling ev_run_list().
|
||||||
|
*/
|
||||||
inline void
|
inline void
|
||||||
ev_enqueue(event_list *l, event *e)
|
ev_enqueue(event_list *l, event *e)
|
||||||
{
|
{
|
||||||
|
@ -64,12 +104,26 @@ ev_enqueue(event_list *l, event *e)
|
||||||
add_tail(l, &e->n);
|
add_tail(l, &e->n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ev_schedule - schedule an event
|
||||||
|
* @e: an event
|
||||||
|
*
|
||||||
|
* This function schedules an event by enqueueing it to a system-wide
|
||||||
|
* event list which is run by the platform dependent code whenever
|
||||||
|
* appropriate.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
ev_schedule(event *e)
|
ev_schedule(event *e)
|
||||||
{
|
{
|
||||||
ev_enqueue(&global_event_list, e);
|
ev_enqueue(&global_event_list, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ev_run_list - run an event list
|
||||||
|
* @l: an event list
|
||||||
|
*
|
||||||
|
* This function calls ev_run() for all events enqueued in the list @l.
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
ev_run_list(event_list *l)
|
ev_run_list(event_list *l)
|
||||||
{
|
{
|
||||||
|
|
|
@ -36,15 +36,7 @@ type.
|
||||||
<item><it/Memory blocks/
|
<item><it/Memory blocks/
|
||||||
<item><it/Linear memory pools/ (<struct/linpool/)
|
<item><it/Linear memory pools/ (<struct/linpool/)
|
||||||
<item><it/Slabs/ (<struct/slab/)
|
<item><it/Slabs/ (<struct/slab/)
|
||||||
<item><it/Sockets/ (<struct/socket/)
|
|
||||||
<item><it/Events/ (<struct/event/)
|
<item><it/Events/ (<struct/event/)
|
||||||
<!--
|
|
||||||
are there to keep track of deferred execution.
|
|
||||||
Since BIRD is single-threaded, it requires long lasting tasks to be split to smaller
|
|
||||||
parts, so that no module can monopolize the CPU. To split such a task, just create
|
|
||||||
an <struct/event/ resource, point it to the function you want to have called and call <func/ev_schedule()/
|
|
||||||
to ask the core to run the event when nothing more important will require attention.
|
|
||||||
The actual implementation is system dependent.
|
|
||||||
-->
|
|
||||||
<item><it/Timers/ (<struct/timer/)
|
<item><it/Timers/ (<struct/timer/)
|
||||||
|
<item><it/Sockets/ (<struct/socket/)
|
||||||
</itemize>
|
</itemize>
|
||||||
|
|
1
nest/Doc
1
nest/Doc
|
@ -9,3 +9,4 @@ S iface.c
|
||||||
S neighbor.c
|
S neighbor.c
|
||||||
S cli.c
|
S cli.c
|
||||||
S locks.c
|
S locks.c
|
||||||
|
# rt-dev.c documented in Protocols chapter
|
||||||
|
|
143
sysdep/unix/io.c
143
sysdep/unix/io.c
|
@ -73,8 +73,23 @@ tracked_fopen(pool *p, char *name, char *mode)
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Timers
|
* DOC: Timers
|
||||||
|
*
|
||||||
|
* Timers are resources which represent a wish of a module to call
|
||||||
|
* a function at the specified time. The platform dependent code
|
||||||
|
* doesn't guarantee the exact timing, only that a timer function
|
||||||
|
* won't be called before the requested time.
|
||||||
|
*
|
||||||
|
* In BIRD, real time is represented by values of the &bird_clock_t type
|
||||||
|
* which are integral numbers corresponding to a number of seconds since
|
||||||
|
* a fixed (but platform dependent) epoch. The current time can be read
|
||||||
|
* from a variable @now with reasonable accuracy.
|
||||||
|
*
|
||||||
|
* Each timer is described by a &timer structure containing a pointer
|
||||||
|
* to the handler function (@hook), data private to this function (@data),
|
||||||
|
* time the function should be called at (@expires, 0 for inactive timers),
|
||||||
|
* for the other fields see |timer.h|.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define NEAR_TIMER_LIMIT 4
|
#define NEAR_TIMER_LIMIT 4
|
||||||
|
@ -115,6 +130,14 @@ static struct resclass tm_class = {
|
||||||
tm_dump
|
tm_dump
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tm_new - create a timer
|
||||||
|
* @p: pool
|
||||||
|
*
|
||||||
|
* This function creates a new timer resource and returns
|
||||||
|
* a pointer to it. To use the timer, you need to fill in
|
||||||
|
* the structure fields and call tm_start() to start timing.
|
||||||
|
*/
|
||||||
timer *
|
timer *
|
||||||
tm_new(pool *p)
|
tm_new(pool *p)
|
||||||
{
|
{
|
||||||
|
@ -136,6 +159,23 @@ tm_insert_near(timer *t)
|
||||||
insert_node(&t->n, n->prev);
|
insert_node(&t->n, n->prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tm_start - start a timer
|
||||||
|
* @t: timer
|
||||||
|
* @after: number of seconds the timer should be run after
|
||||||
|
*
|
||||||
|
* This function schedules the hook function of the timer to
|
||||||
|
* be called after @after seconds. If the timer has been already
|
||||||
|
* started, it's @expire time is replaced by the new value.
|
||||||
|
*
|
||||||
|
* You can have set the @randomize field of @t, the timeout
|
||||||
|
* will be increased by a random number of seconds chosen
|
||||||
|
* uniformly from range 0 .. @randomize.
|
||||||
|
*
|
||||||
|
* You can call tm_start() from the handler function of the timer
|
||||||
|
* to request another run of the timer. Also, you can set the @recurrent
|
||||||
|
* field to have the timer re-added automatically with the same timeout.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
tm_start(timer *t, unsigned after)
|
tm_start(timer *t, unsigned after)
|
||||||
{
|
{
|
||||||
|
@ -159,6 +199,13 @@ tm_start(timer *t, unsigned after)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tm_stop - stop a timer
|
||||||
|
* @t: timer
|
||||||
|
*
|
||||||
|
* This function stops a timer. If the timer is already stopped,
|
||||||
|
* nothing happens.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
tm_stop(timer *t)
|
tm_stop(timer *t)
|
||||||
{
|
{
|
||||||
|
@ -250,6 +297,13 @@ tm_shot(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tm_parse_date - parse a date
|
||||||
|
* @x: date string
|
||||||
|
*
|
||||||
|
* tm_parse_date() takes a textual representation of a date (dd-mm-yyyy)
|
||||||
|
* and converts it to the corresponding value of type &bird_clock_t.
|
||||||
|
*/
|
||||||
bird_clock_t
|
bird_clock_t
|
||||||
tm_parse_date(char *x)
|
tm_parse_date(char *x)
|
||||||
{
|
{
|
||||||
|
@ -268,6 +322,14 @@ tm_parse_date(char *x)
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tm_format_date - convert date to textual representation
|
||||||
|
* @x: destination buffer of size %TM_DATE_BUFFER_SIZE
|
||||||
|
* @t: time
|
||||||
|
*
|
||||||
|
* This function formats the given time value @t to a textual
|
||||||
|
* date representation (dd-mm-yyyy).
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
tm_format_date(char *x, bird_clock_t t)
|
tm_format_date(char *x, bird_clock_t t)
|
||||||
{
|
{
|
||||||
|
@ -277,6 +339,14 @@ tm_format_date(char *x, bird_clock_t t)
|
||||||
bsprintf(x, "%02d-%02d-%04d", tm->tm_mday, tm->tm_mon+1, tm->tm_year+1900);
|
bsprintf(x, "%02d-%02d-%04d", tm->tm_mday, tm->tm_mon+1, tm->tm_year+1900);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tm_format_datetime - convert date and time to textual representation
|
||||||
|
* @x: destination buffer of size %TM_DATETIME_BUFFER_SIZE
|
||||||
|
* @t: time
|
||||||
|
*
|
||||||
|
* This function formats the given time value @t to a textual
|
||||||
|
* date/time representation (dd-mm-yyyy hh:mm:ss).
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
tm_format_datetime(char *x, bird_clock_t t)
|
tm_format_datetime(char *x, bird_clock_t t)
|
||||||
{
|
{
|
||||||
|
@ -287,6 +357,14 @@ tm_format_datetime(char *x, bird_clock_t t)
|
||||||
strcpy(x, "<too-long>");
|
strcpy(x, "<too-long>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tm_format_reltime - convert date and time to relative textual representation
|
||||||
|
* @x: destination buffer of size %TM_RELTIME_BUFFER_SIZE
|
||||||
|
* @t: time
|
||||||
|
*
|
||||||
|
* This function formats the given time value @t to a short
|
||||||
|
* textual representation relative to the current time.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
tm_format_reltime(char *x, bird_clock_t t)
|
tm_format_reltime(char *x, bird_clock_t t)
|
||||||
{
|
{
|
||||||
|
@ -303,8 +381,17 @@ tm_format_reltime(char *x, bird_clock_t t)
|
||||||
bsprintf(x, "%d", tm->tm_year+1900);
|
bsprintf(x, "%d", tm->tm_year+1900);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Sockets
|
* DOC: Sockets
|
||||||
|
*
|
||||||
|
* Socket resources represent network connections. Their data structure (&socket)
|
||||||
|
* contains a lot of fields defining the exact type of the socket, the local and
|
||||||
|
* remote addresses and ports, pointers to socket buffers and finally pointers to
|
||||||
|
* hook functions to be called when new data have arrived to the receive buffer
|
||||||
|
* (@rx_hook), when the contents of the transmit buffer have been transmitted
|
||||||
|
* (@tx_hook) and when an error or connection close occurs (@err_hook).
|
||||||
|
*
|
||||||
|
* You should not use rfree() from inside a socket hook, please use sk_close() instead.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SOL_IP
|
#ifndef SOL_IP
|
||||||
|
@ -350,6 +437,14 @@ static struct resclass sk_class = {
|
||||||
sk_dump
|
sk_dump
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sk_new - create a socket
|
||||||
|
* @p: pool
|
||||||
|
*
|
||||||
|
* This function creates a new socket resource. If you want to use it,
|
||||||
|
* you need to fill in all the required fields of the structure and
|
||||||
|
* call sk_open() to do the actual opening of the socket.
|
||||||
|
*/
|
||||||
sock *
|
sock *
|
||||||
sk_new(pool *p)
|
sk_new(pool *p)
|
||||||
{
|
{
|
||||||
|
@ -502,6 +597,16 @@ sk_passive_connected(sock *s, struct sockaddr *sa, int al, int type)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sk_open - open a socket
|
||||||
|
* @s: socket
|
||||||
|
*
|
||||||
|
* This function takes a socket resource created by sk_new() and
|
||||||
|
* initialized by the user and binds a corresponding network connection
|
||||||
|
* to it.
|
||||||
|
*
|
||||||
|
* Result: 0 for success, -1 for an error.
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
sk_open(sock *s)
|
sk_open(sock *s)
|
||||||
{
|
{
|
||||||
|
@ -683,6 +788,14 @@ bad:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sk_close - close a socket
|
||||||
|
* @s: a socket
|
||||||
|
*
|
||||||
|
* If sk_close() has been called from outside of any socket hook,
|
||||||
|
* it translates to a rfree(), else it just marks the socket for
|
||||||
|
* deletion as soon as the socket hook returns.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
sk_close(sock *s)
|
sk_close(sock *s)
|
||||||
{
|
{
|
||||||
|
@ -746,6 +859,18 @@ sk_maybe_write(sock *s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sk_send - send data to a socket
|
||||||
|
* @s: socket
|
||||||
|
* @len: number of bytes to send
|
||||||
|
*
|
||||||
|
* This function sends @len bytes of data prepared in the
|
||||||
|
* transmit buffer of the socket @s to the network connection.
|
||||||
|
* If the packet can be sent immediately, it does so and returns
|
||||||
|
* 1, else it queues the packet for later processing, returns 0
|
||||||
|
* and calls the @tx_hook of the socket when the tranmission
|
||||||
|
* takes place.
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
sk_send(sock *s, unsigned len)
|
sk_send(sock *s, unsigned len)
|
||||||
{
|
{
|
||||||
|
@ -756,6 +881,16 @@ sk_send(sock *s, unsigned len)
|
||||||
return sk_maybe_write(s);
|
return sk_maybe_write(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sk_send_to - send data to a specific destination
|
||||||
|
* @s: socket
|
||||||
|
* @len: number of bytes to send
|
||||||
|
* @addr: IP address to send the packet to
|
||||||
|
* @port: port to send the packet to
|
||||||
|
*
|
||||||
|
* This is a sk_send() replacement for connectionless packet sockets
|
||||||
|
* which allows destination of the packet to be chosen dynamically.
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
sk_send_to(sock *s, unsigned len, ip_addr addr, unsigned port)
|
sk_send_to(sock *s, unsigned len, ip_addr addr, unsigned port)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue