Annotation of embedaddon/libevent/event.3, revision 1.1
1.1 ! misho 1: .\" $OpenBSD: event.3,v 1.4 2002/07/12 18:50:48 provos Exp $
! 2: .\"
! 3: .\" Copyright (c) 2000 Artur Grabowski <art@openbsd.org>
! 4: .\" All rights reserved.
! 5: .\"
! 6: .\" Redistribution and use in source and binary forms, with or without
! 7: .\" modification, are permitted provided that the following conditions
! 8: .\" are met:
! 9: .\"
! 10: .\" 1. Redistributions of source code must retain the above copyright
! 11: .\" notice, this list of conditions and the following disclaimer.
! 12: .\" 2. Redistributions in binary form must reproduce the above copyright
! 13: .\" notice, this list of conditions and the following disclaimer in the
! 14: .\" documentation and/or other materials provided with the distribution.
! 15: .\" 3. The name of the author may not be used to endorse or promote products
! 16: .\" derived from this software without specific prior written permission.
! 17: .\"
! 18: .\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
! 19: .\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
! 20: .\" AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
! 21: .\" THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
! 22: .\" EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
! 23: .\" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
! 24: .\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
! 25: .\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
! 26: .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
! 27: .\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 28: .\"
! 29: .Dd August 8, 2000
! 30: .Dt EVENT 3
! 31: .Os
! 32: .Sh NAME
! 33: .Nm event_init ,
! 34: .Nm event_dispatch ,
! 35: .Nm event_loop ,
! 36: .Nm event_loopexit ,
! 37: .Nm event_loopbreak ,
! 38: .Nm event_set ,
! 39: .Nm event_base_dispatch ,
! 40: .Nm event_base_loop ,
! 41: .Nm event_base_loopexit ,
! 42: .Nm event_base_loopbreak ,
! 43: .Nm event_base_set ,
! 44: .Nm event_base_free ,
! 45: .Nm event_add ,
! 46: .Nm event_del ,
! 47: .Nm event_once ,
! 48: .Nm event_base_once ,
! 49: .Nm event_pending ,
! 50: .Nm event_initialized ,
! 51: .Nm event_priority_init ,
! 52: .Nm event_priority_set ,
! 53: .Nm evtimer_set ,
! 54: .Nm evtimer_add ,
! 55: .Nm evtimer_del ,
! 56: .Nm evtimer_pending ,
! 57: .Nm evtimer_initialized ,
! 58: .Nm signal_set ,
! 59: .Nm signal_add ,
! 60: .Nm signal_del ,
! 61: .Nm signal_pending ,
! 62: .Nm signal_initialized ,
! 63: .Nm bufferevent_new ,
! 64: .Nm bufferevent_free ,
! 65: .Nm bufferevent_write ,
! 66: .Nm bufferevent_write_buffer ,
! 67: .Nm bufferevent_read ,
! 68: .Nm bufferevent_enable ,
! 69: .Nm bufferevent_disable ,
! 70: .Nm bufferevent_settimeout ,
! 71: .Nm bufferevent_base_set ,
! 72: .Nm evbuffer_new ,
! 73: .Nm evbuffer_free ,
! 74: .Nm evbuffer_add ,
! 75: .Nm evbuffer_add_buffer ,
! 76: .Nm evbuffer_add_printf ,
! 77: .Nm evbuffer_add_vprintf ,
! 78: .Nm evbuffer_drain ,
! 79: .Nm evbuffer_write ,
! 80: .Nm evbuffer_read ,
! 81: .Nm evbuffer_find ,
! 82: .Nm evbuffer_readline ,
! 83: .Nm evhttp_new ,
! 84: .Nm evhttp_bind_socket ,
! 85: .Nm evhttp_free
! 86: .Nd execute a function when a specific event occurs
! 87: .Sh SYNOPSIS
! 88: .Fd #include <sys/time.h>
! 89: .Fd #include <event.h>
! 90: .Ft "struct event_base *"
! 91: .Fn "event_init" "void"
! 92: .Ft int
! 93: .Fn "event_dispatch" "void"
! 94: .Ft int
! 95: .Fn "event_loop" "int flags"
! 96: .Ft int
! 97: .Fn "event_loopexit" "struct timeval *tv"
! 98: .Ft int
! 99: .Fn "event_loopbreak" "void"
! 100: .Ft void
! 101: .Fn "event_set" "struct event *ev" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg"
! 102: .Ft int
! 103: .Fn "event_base_dispatch" "struct event_base *base"
! 104: .Ft int
! 105: .Fn "event_base_loop" "struct event_base *base" "int flags"
! 106: .Ft int
! 107: .Fn "event_base_loopexit" "struct event_base *base" "struct timeval *tv"
! 108: .Ft int
! 109: .Fn "event_base_loopbreak" "struct event_base *base"
! 110: .Ft int
! 111: .Fn "event_base_set" "struct event_base *base" "struct event *"
! 112: .Ft void
! 113: .Fn "event_base_free" "struct event_base *base"
! 114: .Ft int
! 115: .Fn "event_add" "struct event *ev" "struct timeval *tv"
! 116: .Ft int
! 117: .Fn "event_del" "struct event *ev"
! 118: .Ft int
! 119: .Fn "event_once" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg" "struct timeval *tv"
! 120: .Ft int
! 121: .Fn "event_base_once" "struct event_base *base" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg" "struct timeval *tv"
! 122: .Ft int
! 123: .Fn "event_pending" "struct event *ev" "short event" "struct timeval *tv"
! 124: .Ft int
! 125: .Fn "event_initialized" "struct event *ev"
! 126: .Ft int
! 127: .Fn "event_priority_init" "int npriorities"
! 128: .Ft int
! 129: .Fn "event_priority_set" "struct event *ev" "int priority"
! 130: .Ft void
! 131: .Fn "evtimer_set" "struct event *ev" "void (*fn)(int, short, void *)" "void *arg"
! 132: .Ft void
! 133: .Fn "evtimer_add" "struct event *ev" "struct timeval *"
! 134: .Ft void
! 135: .Fn "evtimer_del" "struct event *ev"
! 136: .Ft int
! 137: .Fn "evtimer_pending" "struct event *ev" "struct timeval *tv"
! 138: .Ft int
! 139: .Fn "evtimer_initialized" "struct event *ev"
! 140: .Ft void
! 141: .Fn "signal_set" "struct event *ev" "int signal" "void (*fn)(int, short, void *)" "void *arg"
! 142: .Ft void
! 143: .Fn "signal_add" "struct event *ev" "struct timeval *"
! 144: .Ft void
! 145: .Fn "signal_del" "struct event *ev"
! 146: .Ft int
! 147: .Fn "signal_pending" "struct event *ev" "struct timeval *tv"
! 148: .Ft int
! 149: .Fn "signal_initialized" "struct event *ev"
! 150: .Ft "struct bufferevent *"
! 151: .Fn "bufferevent_new" "int fd" "evbuffercb readcb" "evbuffercb writecb" "everrorcb" "void *cbarg"
! 152: .Ft void
! 153: .Fn "bufferevent_free" "struct bufferevent *bufev"
! 154: .Ft int
! 155: .Fn "bufferevent_write" "struct bufferevent *bufev" "void *data" "size_t size"
! 156: .Ft int
! 157: .Fn "bufferevent_write_buffer" "struct bufferevent *bufev" "struct evbuffer *buf"
! 158: .Ft size_t
! 159: .Fn "bufferevent_read" "struct bufferevent *bufev" "void *data" "size_t size"
! 160: .Ft int
! 161: .Fn "bufferevent_enable" "struct bufferevent *bufev" "short event"
! 162: .Ft int
! 163: .Fn "bufferevent_disable" "struct bufferevent *bufev" "short event"
! 164: .Ft void
! 165: .Fn "bufferevent_settimeout" "struct bufferevent *bufev" "int timeout_read" "int timeout_write"
! 166: .Ft int
! 167: .Fn "bufferevent_base_set" "struct event_base *base" "struct bufferevent *bufev"
! 168: .Ft "struct evbuffer *"
! 169: .Fn "evbuffer_new" "void"
! 170: .Ft void
! 171: .Fn "evbuffer_free" "struct evbuffer *buf"
! 172: .Ft int
! 173: .Fn "evbuffer_add" "struct evbuffer *buf" "const void *data" "size_t size"
! 174: .Ft int
! 175: .Fn "evbuffer_add_buffer" "struct evbuffer *dst" "struct evbuffer *src"
! 176: .Ft int
! 177: .Fn "evbuffer_add_printf" "struct evbuffer *buf" "const char *fmt" "..."
! 178: .Ft int
! 179: .Fn "evbuffer_add_vprintf" "struct evbuffer *buf" "const char *fmt" "va_list ap"
! 180: .Ft void
! 181: .Fn "evbuffer_drain" "struct evbuffer *buf" "size_t size"
! 182: .Ft int
! 183: .Fn "evbuffer_write" "struct evbuffer *buf" "int fd"
! 184: .Ft int
! 185: .Fn "evbuffer_read" "struct evbuffer *buf" "int fd" "int size"
! 186: .Ft "u_char *"
! 187: .Fn "evbuffer_find" "struct evbuffer *buf" "const u_char *data" "size_t size"
! 188: .Ft "char *"
! 189: .Fn "evbuffer_readline" "struct evbuffer *buf"
! 190: .Ft "struct evhttp *"
! 191: .Fn "evhttp_new" "struct event_base *base"
! 192: .Ft int
! 193: .Fn "evhttp_bind_socket" "struct evhttp *http" "const char *address" "u_short port"
! 194: .Ft "void"
! 195: .Fn "evhttp_free" "struct evhttp *http"
! 196: .Ft int
! 197: .Fa (*event_sigcb)(void) ;
! 198: .Ft volatile sig_atomic_t
! 199: .Fa event_gotsig ;
! 200: .Sh DESCRIPTION
! 201: The
! 202: .Nm event
! 203: API provides a mechanism to execute a function when a specific event
! 204: on a file descriptor occurs or after a given time has passed.
! 205: .Pp
! 206: The
! 207: .Nm event
! 208: API needs to be initialized with
! 209: .Fn event_init
! 210: before it can be used.
! 211: .Pp
! 212: In order to process events, an application needs to call
! 213: .Fn event_dispatch .
! 214: This function only returns on error, and should replace the event core
! 215: of the application program.
! 216: .Pp
! 217: The function
! 218: .Fn event_set
! 219: prepares the event structure
! 220: .Fa ev
! 221: to be used in future calls to
! 222: .Fn event_add
! 223: and
! 224: .Fn event_del .
! 225: The event will be prepared to call the function specified by the
! 226: .Fa fn
! 227: argument with an
! 228: .Fa int
! 229: argument indicating the file descriptor, a
! 230: .Fa short
! 231: argument indicating the type of event, and a
! 232: .Fa void *
! 233: argument given in the
! 234: .Fa arg
! 235: argument.
! 236: The
! 237: .Fa fd
! 238: indicates the file descriptor that should be monitored for events.
! 239: The events can be either
! 240: .Va EV_READ ,
! 241: .Va EV_WRITE ,
! 242: or both,
! 243: indicating that an application can read or write from the file descriptor
! 244: respectively without blocking.
! 245: .Pp
! 246: The function
! 247: .Fa fn
! 248: will be called with the file descriptor that triggered the event and
! 249: the type of event which will be either
! 250: .Va EV_TIMEOUT ,
! 251: .Va EV_SIGNAL ,
! 252: .Va EV_READ ,
! 253: or
! 254: .Va EV_WRITE .
! 255: Additionally, an event which has registered interest in more than one of the
! 256: preceeding events, via bitwise-OR to
! 257: .Fn event_set ,
! 258: can provide its callback function with a bitwise-OR of more than one triggered
! 259: event.
! 260: The additional flag
! 261: .Va EV_PERSIST
! 262: makes an
! 263: .Fn event_add
! 264: persistent until
! 265: .Fn event_del
! 266: has been called.
! 267: .Pp
! 268: Once initialized, the
! 269: .Fa ev
! 270: structure can be used repeatedly with
! 271: .Fn event_add
! 272: and
! 273: .Fn event_del
! 274: and does not need to be reinitialized unless the function called and/or
! 275: the argument to it are to be changed.
! 276: However, when an
! 277: .Fa ev
! 278: structure has been added to libevent using
! 279: .Fn event_add
! 280: the structure must persist until the event occurs (assuming
! 281: .Fa EV_PERSIST
! 282: is not set) or is removed
! 283: using
! 284: .Fn event_del .
! 285: You may not reuse the same
! 286: .Fa ev
! 287: structure for multiple monitored descriptors; each descriptor
! 288: needs its own
! 289: .Fa ev .
! 290: .Pp
! 291: The function
! 292: .Fn event_add
! 293: schedules the execution of the
! 294: .Fa ev
! 295: event when the event specified in
! 296: .Fn event_set
! 297: occurs or in at least the time specified in the
! 298: .Fa tv .
! 299: If
! 300: .Fa tv
! 301: is
! 302: .Dv NULL ,
! 303: no timeout occurs and the function will only be called
! 304: if a matching event occurs on the file descriptor.
! 305: The event in the
! 306: .Fa ev
! 307: argument must be already initialized by
! 308: .Fn event_set
! 309: and may not be used in calls to
! 310: .Fn event_set
! 311: until it has timed out or been removed with
! 312: .Fn event_del .
! 313: If the event in the
! 314: .Fa ev
! 315: argument already has a scheduled timeout, the old timeout will be
! 316: replaced by the new one.
! 317: .Pp
! 318: The function
! 319: .Fn event_del
! 320: will cancel the event in the argument
! 321: .Fa ev .
! 322: If the event has already executed or has never been added
! 323: the call will have no effect.
! 324: .Pp
! 325: The functions
! 326: .Fn evtimer_set ,
! 327: .Fn evtimer_add ,
! 328: .Fn evtimer_del ,
! 329: .Fn evtimer_initialized ,
! 330: and
! 331: .Fn evtimer_pending
! 332: are abbreviations for common situations where only a timeout is required.
! 333: The file descriptor passed will be \-1, and the event type will be
! 334: .Va EV_TIMEOUT .
! 335: .Pp
! 336: The functions
! 337: .Fn signal_set ,
! 338: .Fn signal_add ,
! 339: .Fn signal_del ,
! 340: .Fn signal_initialized ,
! 341: and
! 342: .Fn signal_pending
! 343: are abbreviations.
! 344: The event type will be a persistent
! 345: .Va EV_SIGNAL .
! 346: That means
! 347: .Fn signal_set
! 348: adds
! 349: .Va EV_PERSIST .
! 350: .Pp
! 351: In order to avoid races in signal handlers, the
! 352: .Nm event
! 353: API provides two variables:
! 354: .Va event_sigcb
! 355: and
! 356: .Va event_gotsig .
! 357: A signal handler
! 358: sets
! 359: .Va event_gotsig
! 360: to indicate that a signal has been received.
! 361: The application sets
! 362: .Va event_sigcb
! 363: to a callback function.
! 364: After the signal handler sets
! 365: .Va event_gotsig ,
! 366: .Nm event_dispatch
! 367: will execute the callback function to process received signals.
! 368: The callback returns 1 when no events are registered any more.
! 369: It can return \-1 to indicate an error to the
! 370: .Nm event
! 371: library, causing
! 372: .Fn event_dispatch
! 373: to terminate with
! 374: .Va errno
! 375: set to
! 376: .Er EINTR .
! 377: .Pp
! 378: The function
! 379: .Fn event_once
! 380: is similar to
! 381: .Fn event_set .
! 382: However, it schedules a callback to be called exactly once and does not
! 383: require the caller to prepare an
! 384: .Fa event
! 385: structure.
! 386: This function supports
! 387: .Fa EV_TIMEOUT ,
! 388: .Fa EV_READ ,
! 389: and
! 390: .Fa EV_WRITE .
! 391: .Pp
! 392: The
! 393: .Fn event_pending
! 394: function can be used to check if the event specified by
! 395: .Fa event
! 396: is pending to run.
! 397: If
! 398: .Va EV_TIMEOUT
! 399: was specified and
! 400: .Fa tv
! 401: is not
! 402: .Dv NULL ,
! 403: the expiration time of the event will be returned in
! 404: .Fa tv .
! 405: .Pp
! 406: The
! 407: .Fn event_initialized
! 408: macro can be used to check if an event has been initialized.
! 409: .Pp
! 410: The
! 411: .Nm event_loop
! 412: function provides an interface for single pass execution of pending
! 413: events.
! 414: The flags
! 415: .Va EVLOOP_ONCE
! 416: and
! 417: .Va EVLOOP_NONBLOCK
! 418: are recognized.
! 419: The
! 420: .Nm event_loopexit
! 421: function exits from the event loop. The next
! 422: .Fn event_loop
! 423: iteration after the
! 424: given timer expires will complete normally (handling all queued events) then
! 425: exit without blocking for events again. Subsequent invocations of
! 426: .Fn event_loop
! 427: will proceed normally.
! 428: The
! 429: .Nm event_loopbreak
! 430: function exits from the event loop immediately.
! 431: .Fn event_loop
! 432: will abort after the next event is completed;
! 433: .Fn event_loopbreak
! 434: is typically invoked from this event's callback. This behavior is analogous
! 435: to the "break;" statement. Subsequent invocations of
! 436: .Fn event_loop
! 437: will proceed normally.
! 438: .Pp
! 439: It is the responsibility of the caller to provide these functions with
! 440: pre-allocated event structures.
! 441: .Pp
! 442: .Sh EVENT PRIORITIES
! 443: By default
! 444: .Nm libevent
! 445: schedules all active events with the same priority.
! 446: However, sometimes it is desirable to process some events with a higher
! 447: priority than others.
! 448: For that reason,
! 449: .Nm libevent
! 450: supports strict priority queues.
! 451: Active events with a lower priority are always processed before events
! 452: with a higher priority.
! 453: .Pp
! 454: The number of different priorities can be set initially with the
! 455: .Fn event_priority_init
! 456: function.
! 457: This function should be called before the first call to
! 458: .Fn event_dispatch .
! 459: The
! 460: .Fn event_priority_set
! 461: function can be used to assign a priority to an event.
! 462: By default,
! 463: .Nm libevent
! 464: assigns the middle priority to all events unless their priority
! 465: is explicitly set.
! 466: .Sh THREAD SAFE EVENTS
! 467: .Nm Libevent
! 468: has experimental support for thread-safe events.
! 469: When initializing the library via
! 470: .Fn event_init ,
! 471: an event base is returned.
! 472: This event base can be used in conjunction with calls to
! 473: .Fn event_base_set ,
! 474: .Fn event_base_dispatch ,
! 475: .Fn event_base_loop ,
! 476: .Fn event_base_loopexit ,
! 477: .Fn bufferevent_base_set
! 478: and
! 479: .Fn event_base_free .
! 480: .Fn event_base_set
! 481: should be called after preparing an event with
! 482: .Fn event_set ,
! 483: as
! 484: .Fn event_set
! 485: assigns the provided event to the most recently created event base.
! 486: .Fn bufferevent_base_set
! 487: should be called after preparing a bufferevent with
! 488: .Fn bufferevent_new .
! 489: .Fn event_base_free
! 490: should be used to free memory associated with the event base
! 491: when it is no longer needed.
! 492: .Sh BUFFERED EVENTS
! 493: .Nm libevent
! 494: provides an abstraction on top of the regular event callbacks.
! 495: This abstraction is called a
! 496: .Va "buffered event" .
! 497: A buffered event provides input and output buffers that get filled
! 498: and drained automatically.
! 499: The user of a buffered event no longer deals directly with the IO,
! 500: but instead is reading from input and writing to output buffers.
! 501: .Pp
! 502: A new bufferevent is created by
! 503: .Fn bufferevent_new .
! 504: The parameter
! 505: .Fa fd
! 506: specifies the file descriptor from which data is read and written to.
! 507: This file descriptor is not allowed to be a
! 508: .Xr pipe 2 .
! 509: The next three parameters are callbacks.
! 510: The read and write callback have the following form:
! 511: .Ft void
! 512: .Fn "(*cb)" "struct bufferevent *bufev" "void *arg" .
! 513: The error callback has the following form:
! 514: .Ft void
! 515: .Fn "(*cb)" "struct bufferevent *bufev" "short what" "void *arg" .
! 516: The argument is specified by the fourth parameter
! 517: .Fa "cbarg" .
! 518: A
! 519: .Fa bufferevent struct
! 520: pointer is returned on success, NULL on error.
! 521: Both the read and the write callback may be NULL.
! 522: The error callback has to be always provided.
! 523: .Pp
! 524: Once initialized, the bufferevent structure can be used repeatedly with
! 525: bufferevent_enable() and bufferevent_disable().
! 526: The flags parameter can be a combination of
! 527: .Va EV_READ
! 528: and
! 529: .Va EV_WRITE .
! 530: When read enabled the bufferevent will try to read from the file
! 531: descriptor and call the read callback.
! 532: The write callback is executed
! 533: whenever the output buffer is drained below the write low watermark,
! 534: which is
! 535: .Va 0
! 536: by default.
! 537: .Pp
! 538: The
! 539: .Fn bufferevent_write
! 540: function can be used to write data to the file descriptor.
! 541: The data is appended to the output buffer and written to the descriptor
! 542: automatically as it becomes available for writing.
! 543: .Fn bufferevent_write
! 544: returns 0 on success or \-1 on failure.
! 545: The
! 546: .Fn bufferevent_read
! 547: function is used to read data from the input buffer,
! 548: returning the amount of data read.
! 549: .Pp
! 550: If multiple bases are in use, bufferevent_base_set() must be called before
! 551: enabling the bufferevent for the first time.
! 552: .Sh NON-BLOCKING HTTP SUPPORT
! 553: .Nm libevent
! 554: provides a very thin HTTP layer that can be used both to host an HTTP
! 555: server and also to make HTTP requests.
! 556: An HTTP server can be created by calling
! 557: .Fn evhttp_new .
! 558: It can be bound to any port and address with the
! 559: .Fn evhttp_bind_socket
! 560: function.
! 561: When the HTTP server is no longer used, it can be freed via
! 562: .Fn evhttp_free .
! 563: .Pp
! 564: To be notified of HTTP requests, a user needs to register callbacks with the
! 565: HTTP server.
! 566: This can be done by calling
! 567: .Fn evhttp_set_cb .
! 568: The second argument is the URI for which a callback is being registered.
! 569: The corresponding callback will receive an
! 570: .Va struct evhttp_request
! 571: object that contains all information about the request.
! 572: .Pp
! 573: This section does not document all the possible function calls; please
! 574: check
! 575: .Va event.h
! 576: for the public interfaces.
! 577: .Sh ADDITIONAL NOTES
! 578: It is possible to disable support for
! 579: .Va epoll , kqueue , devpoll , poll
! 580: or
! 581: .Va select
! 582: by setting the environment variable
! 583: .Va EVENT_NOEPOLL , EVENT_NOKQUEUE , EVENT_NODEVPOLL , EVENT_NOPOLL
! 584: or
! 585: .Va EVENT_NOSELECT ,
! 586: respectively.
! 587: By setting the environment variable
! 588: .Va EVENT_SHOW_METHOD ,
! 589: .Nm libevent
! 590: displays the kernel notification method that it uses.
! 591: .Sh RETURN VALUES
! 592: Upon successful completion
! 593: .Fn event_add
! 594: and
! 595: .Fn event_del
! 596: return 0.
! 597: Otherwise, \-1 is returned and the global variable errno is
! 598: set to indicate the error.
! 599: .Sh SEE ALSO
! 600: .Xr kqueue 2 ,
! 601: .Xr poll 2 ,
! 602: .Xr select 2 ,
! 603: .Xr evdns 3 ,
! 604: .Xr timeout 9
! 605: .Sh HISTORY
! 606: The
! 607: .Nm event
! 608: API manpage is based on the
! 609: .Xr timeout 9
! 610: manpage by Artur Grabowski.
! 611: The port of
! 612: .Nm libevent
! 613: to Windows is due to Michael A. Davis.
! 614: Support for real-time signals is due to Taral.
! 615: .Sh AUTHORS
! 616: The
! 617: .Nm event
! 618: library was written by Niels Provos.
! 619: .Sh BUGS
! 620: This documentation is neither complete nor authoritative.
! 621: If you are in doubt about the usage of this API then
! 622: check the source code to find out how it works, write
! 623: up the missing piece of documentation and send it to
! 624: me for inclusion in this man page.
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>