Skip to content

Commit

Permalink
Make all examples compile correctly
Browse files Browse the repository at this point in the history
Inspired by the late William Stevens, who was in turn inspired by
Kernighan and Pike, I decided we needed an automated process to make
sure that all the example code actually would compile.  That's a good
thing: it turns out that nearly none of it did before.
  • Loading branch information
nmathewson committed Jan 29, 2010
1 parent a9ae73e commit 53babe0
Show file tree
Hide file tree
Showing 12 changed files with 468 additions and 314 deletions.
33 changes: 29 additions & 4 deletions 01_intro.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ Here's an example of a really simple client using blocking network
calls. It opens a connection to www.google.com, sends it a simple
HTTP request, and prints the response to stdout.

[code]
//BUILD: SKIP
.Example: A simple blocking HTTP client
[code,C]
-------
include::examples_01/01_sync_webclient.c[]
-------
Expand All @@ -37,16 +39,21 @@ for you. But suppose that you need to write a program to handle
multiple connections at once. To make our example concrete: suppose
that you want to read input from two connections, and you don't know
which connection will get input first. You can't say

//BUILD: FUNCTIONBODY INC:../example_stubs/sec01.h
.Bad Example
[code,C]
-------
/* This won't work. */
char buf[1024];
int i, n;
while (i_still_want_to_read()) {
for (i=0; i<n_sockets; ++i) {
n = recv(fd[i], buf, sizeof(buf), 0);
if (n==0)
handle_close(fd[i]);
else if (n<0)
handle_error(fd[i], error)
handle_error(fd[i], errno);
else
handle_input(fd[i], buf, n);
}
Expand All @@ -69,6 +76,8 @@ at a time, and writes out the ROT13 obfuscation of line each as it
arrives. It uses the Unix fork() call to create a new process for
each incoming connection.

//BUILD: SKIP
.Example: Forking ROT13 server
[code,C]
-------
include::examples_01/01_rot13_server_forking.c[]
Expand Down Expand Up @@ -100,9 +109,13 @@ immediately or return with a special error code to indicate "I
couldn't make any progress now, try again." So our two-socket example
might be naively written as:

//BUILD: FUNCTIONBODY INC:../example_stubs/sec01.h
.Bad Example: busy-polling all sockets
[code,C]
------
/* This will work, but the performance will be unforgivably bad. */
int i, n;
char buf[1024];
for (i=0; i < n_sockets; ++i)
fcntl(fd[i], F_SETFL, O_NONBLOCK);

Expand All @@ -115,7 +128,7 @@ while (i_still_want_to_read()) {
if (errno == EAGAIN)
; /* The kernel didn't have any data for us to read. */
else
handle_error(fd[i]);
handle_error(fd[i], errno);
} else {
handle_input(fd[i], buf, n);
}
Expand All @@ -140,10 +153,15 @@ bit arrays): one for reading, one for writing, and one for
and alters the sets to contain only the sockets ready for use.

Here is our read() example again, using select:

//BUILD: FUNCTIONBODY INC:../example_stubs/sec01.h
.Example: Using select
[code,C]
------
/* If you only have a couple dozen fds, this version won't be awful */
struct fd_set readset;
int i, n;
char buf[1024];

while (i_still_want_to_read()) {
int maxfd = -1;
Expand All @@ -168,7 +186,7 @@ while (i_still_want_to_read()) {
if (errno == EAGAIN)
; /* The kernel didn't have any data for us to read. */
else
handle_error(fd[i]);
handle_error(fd[i], errno);
} else {
handle_input(fd[i], buf, n);
}
Expand All @@ -180,6 +198,9 @@ while (i_still_want_to_read()) {

And here's a reimplementation of our ROT13 server, using select() this
time.

//BUILD: SKIP
.Example: select()-based ROT13 server
[code,C]
------
include::examples_01/01_rot13_server_select.c[]
Expand Down Expand Up @@ -222,6 +243,8 @@ are gone now: instead, we associate and disassociate events with a
struct event_base, which might be implemented in terms of select(),
poll(), epoll(), kqueue(), etc.

//BUILD: SKIP
.Example: A low-level ROT13 server with Libevent
[code,C]
-------
include::examples_01/01_rot13_server_libevent.c[]
Expand Down Expand Up @@ -264,6 +287,8 @@ on Unix.

Here's our ROT13 server one last time, using the bufferevents API.

//BUILD: SKIP
.Example: A simpler ROT13 server with Libevent
[code,C]
-------
include::examples_01/01_rot13_server_bufferevent.c[]
Expand Down
36 changes: 26 additions & 10 deletions Ref1_libsetup.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ NULL as an argument.
.Examples
[code,C]
--------
#include <event2/event.h>
#include <stdio.h>

static void discard_cb(int severity, const char *msg)
{
/* This callback does nothing. */
Expand All @@ -57,7 +60,7 @@ static void write_to_file_cb(int severity, const char *msg)
case _EVENT_LOG_DEBUG: s = "debug"; break;
case _EVENT_LOG_MSG: s = "msg"; break;
case _EVENT_LOG_WARN: s = "warn"; break;
case _EVENT_LOG_ERR: s = "error; break;
case _EVENT_LOG_ERR: s = "error"; break;
default: s = "?"; break; /* never reached */
}
fprintf(logfile, "[%s] %s\n", s, msg);
Expand All @@ -66,7 +69,7 @@ static void write_to_file_cb(int severity, const char *msg)
/* Turn off all logging from Libevent. */
void suppress_logging(void)
{
event_set_log_callback(discard_cb)
event_set_log_callback(discard_cb);
}

/* Redirect all Libevent log messages to the C stdio file 'f'. */
Expand Down Expand Up @@ -139,14 +142,20 @@ when Libevent is running in multiple threads.
.Example
[code,C]
--------
#include <event2/event.h>
#include <sys/types.h>
#include <stdlib.h>

/* This union's purpose is to be as big as the largest of all the
* types it contains. */
union alignment {
size_t sz;
void *ptr;
double dbl;
};
/* We need to make sure that everything we return is on the right
alignment to hold anything, including a double. */
#define ALIGNMENT sizeof(alignment)
#define ALIGNMENT sizeof(union alignment)

/* We need to do this cast-to-char* trick on our pointers to adjust
them; doing arithmetic on a void* is not standard. */
Expand Down Expand Up @@ -174,11 +183,11 @@ static void *replacement_realloc(void *ptr, size_t sz)
return NULL;
*(size_t*)ptr = sz;
total_allocated = total_allocated - old_size + sz;
return OUTPTR(chunk);
return OUTPTR(ptr);
}
static void replacement_free(void *ptr)
{
ptr = INPTR(chunk);
ptr = INPTR(ptr);
total_allocated -= *(size_t*)ptr;
free(ptr);
}
Expand Down Expand Up @@ -244,7 +253,7 @@ code, you're in luck. There are pre-defined functions that will set Libevent
up to use the right pthreads or Windows functions for you.

.Interface
[code]
[code,C]
--------
#ifdef WIN32
int evthread_use_windows_threads(void);
Expand Down Expand Up @@ -377,7 +386,7 @@ errors, including:
If one of these lock errors occurs, Libevent exits with an assertion failure.

.Interface
[Code,C]
[code,C]
-----
void evthread_enable_lock_debuging(void);
-----
Expand All @@ -397,7 +406,7 @@ you'll want to detect the Libevent version, so that you can:
bugs, or work around them.

.Interface
[code]
[code,C]
--------
#define LIBEVENT_VERSION_NUMBER 0x02000300
#define LIBEVENT_VERSION "0.2.0.3-alpha"
Expand All @@ -422,8 +431,10 @@ Thus, the released Libevent 2.0.1-alpha has the version number of [02 00
2.0.2-alpha might have a version number of [02 00 01 08], or 0x02000108.

.Example: Compile-time checks
[code]
[code,C]
--------
#include <event2/event.h>

#if !defined(LIBEVENT_VERSION_NUMBER) || LIBEVENT_VERSION_NUMBER < 0x02000100
#error "This version of Libevent is not supported; Get 2.0.1-alpha or later."
#endif
Expand All @@ -443,8 +454,11 @@ make_sandwich(void)
--------

.Example: Run-time checks
[code]
[code,C]
--------
#include <event2/event.h>
#include <string.h>

int
check_for_old_version(void)
{
Expand Down Expand Up @@ -475,7 +489,9 @@ check_version_match(void)
printf("Running with a Libevent version (%s) very different from the "
"one we were built with (%s).\n", event_get_version(),
LIBEVENT_VERSION);
return -1;
}
return 0;
}
--------

Expand Down
21 changes: 13 additions & 8 deletions Ref2_eventbase.txt
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,13 @@ O(1) backend for Windows, and no backend on Linux that provides both
EV_FEATURE_FDS and EV_FEATURE_O1. If you have made a configuration that
Libevent can't satisfy, event_base_new_with_config() will return NULL.


//BUILD: FUNCTIONBODY INC:event2/event.h
.Example
[code,C]
--------
struct event_config *cfg;
struct event_config *base;
struct event_base *base;
int i;

/* My program wants to use edge-triggered events if at all possible. So
Expand Down Expand Up @@ -191,6 +193,7 @@ The event_get_supported_methods() function returns a pointer to an array of
the names of the methods supported in this version of Libevent. The
last element in the array is NULL.

//BUILD: FUNCTIONBODY INC:event2/event.h
.Example
[code,C]
--------
Expand Down Expand Up @@ -219,11 +222,12 @@ The event_base_get_method() call returns the name of the actual method in use
by an event_base. The event_base_get_features() call returns a bitmask of
the features that it supports.

//BUILD: FUNCTIONBODY INC:event2/event.h
.Example
[code]
[code,C]
--------
struct event_base *base;
enum event_method_features f;
enum event_method_feature f;

base = event_base_new();
if (!base) {
Expand Down Expand Up @@ -253,7 +257,7 @@ When you are finished with an event_base, you can deallocate it with
event_base_free().

.Interface
[code]
[code,C]
--------
void event_base_free(struct event_base *base);
--------
Expand All @@ -274,7 +278,7 @@ though, an event_base supports only a single priority level. You can set the
number of priorities on an event_base by calling event_base_priority_init().

.Interface
[code]
[code,C]
--------
int event_base_priority_init(struct event_base *base, int n_priorities);
--------
Expand Down Expand Up @@ -309,15 +313,16 @@ and you want to continue using an event_base after you have forked, you may
need to reinitialize it.

.Interface
[code]
[code,C]
--------
int event_reinit(struct event_base *base);
--------

The function returns 0 on success, -1 on failure.

//BUILD: FUNCTIONBODY INC:event2/event.h INC:../example_stubs/Ref2.h INC:unistd.h
.Example
[code]
[code,C]
--------
struct event_base *base = event_base_new();

Expand Down Expand Up @@ -349,7 +354,7 @@ threadsafe, this could get pretty error-prone.
Instead of event_base_new(), there was:

.Interface
[code]
[code,C]
--------
struct event_base *event_init(void);
--------
Expand Down
Loading

0 comments on commit 53babe0

Please sign in to comment.