Permalink
Browse files

Make all examples compile correctly

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...
1 parent a9ae73e commit 53babe01f4e72398d524888ac6e7d5c2c013dd3c Nick Mathewson committed Jan 29, 2010
Showing with 468 additions and 314 deletions.
  1. +29 −4 01_intro.txt
  2. +26 −10 Ref1_libsetup.txt
  3. +13 −8 Ref2_eventbase.txt
  4. +31 −36 Ref3_eventloop.txt
  5. +69 −52 Ref4_event.txt
  6. +18 −17 Ref5_evutil.txt
  7. +84 −54 Ref6_bufferevent.txt
  8. +162 −128 Ref7_evbuffer.txt
  9. +7 −5 Ref8_listener.txt
  10. +4 −0 example_stubs/Ref2.h
  11. +11 −0 example_stubs/Ref7.h
  12. +14 −0 example_stubs/sec01.h
View
@@ -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[]
-------
@@ -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);
}
@@ -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[]
@@ -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);
@@ -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);
}
@@ -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;
@@ -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);
}
@@ -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[]
@@ -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[]
@@ -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[]
View
@@ -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. */
@@ -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);
@@ -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'. */
@@ -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. */
@@ -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);
}
@@ -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);
@@ -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);
-----
@@ -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"
@@ -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
@@ -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)
{
@@ -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;
}
--------
View
@@ -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
@@ -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]
--------
@@ -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) {
@@ -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);
--------
@@ -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);
--------
@@ -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();
@@ -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);
--------
Oops, something went wrong.

0 comments on commit 53babe0

Please sign in to comment.