AC_CHECK_HEADERS(sys/param.h sys/fcntl.h sys/file.h sys/ioctl.h sys/time.h)
AC_CHECK_HEADERS(sys/mnttab.h sys/statvfs.h sys/stat.h sys/vfs.h)
AC_CHECK_HEADERS(sys/termios.h sys/types.h sys/errno.h sys/uio.h sys/filio.h)
+dnl Checks for header files, conformed to be required as of 2011
+AC_CHECK_HEADERS(sys/epoll.h)
+
AC_CHECK_HEADER(sys/cdefs.h,,
AC_MSG_RESULT([enabling generic cdefs.h from tree])
CFLAGS="-I\$(top_srcdir)/sys/generic $CFLAGS"
libatalk/netddp/Makefile
libatalk/util/Makefile
libatalk/talloc/Makefile
+ libatalk/tevent/Makefile
libatalk/tdb/Makefile
libatalk/unicode/Makefile
libatalk/unicode/charsets/Makefile
# Makefile.am for include/atalk/
atalkincludedir = $(includedir)/atalk
+
atalkinclude_HEADERS = \
- adouble.h vfs.h aep.h afp.h asp.h atp.h boolean.h \
- cnid.h compat.h ddp.h dsi.h ldapconfig.h list.h logger.h \
- nbp.h netddp.h pap.h paths.h queue.h rtmp.h server_child.h \
- server_ipc.h tdb.h uam.h unicode.h util.h uuid.h volinfo.h \
- zip.h ea.h acl.h unix.h directory.h hash.h volume.h
+ adouble.h \
+ afp.h \
+ vfs.h \
+ cnid.h \
+ logger.h \
+ paths.h \
+ unicode.h \
+ util.h \
+ volinfo.h \
+ ea.h \
+ acl.h \
+ unix.h \
+ volume.h
-noinst_HEADERS = cnid_dbd_private.h cnid_private.h bstradd.h bstrlib.h errchk.h ftw.h
+noinst_HEADERS = \
+ directory.h \
+ hash.h \
+ zip.h \
+ uuid.h \
+ queue.h \
+ rtmp.h \
+ server_child.h \
+ server_ipc.h \
+ tdb.h \
+ uam.h \
+ nbp.h \
+ netddp.h \
+ pap.h \
+ cnid_dbd_private.h \
+ cnid_private.h \
+ bstradd.h \
+ bstrlib.h \
+ errchk.h \
+ ftw.h \
+ talloc.h \
+ tevent.h \
+ aep.h \
+ asp.h \
+ atp.h \
+ boolean.h \
+ compat.h \
+ ddp.h \
+ dsi.h \
+ ldapconfig.h \
+ list.h
--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+
+ generalised event loop handling
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Stefan Metzmacher 2005-2009
+ Copyright (C) Volker Lendecke 2008
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __TEVENT_H__
+#define __TEVENT_H__
+
+#include "config.h"
+
+#include <stdint.h>
+#include <sys/time.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <poll.h>
+#include <signal.h>
+#ifdef HAVE_SYS_EPOLL_H
+#include <sys/epoll.h>
+#endif
+
+#include <atalk/talloc.h>
+
+struct tevent_context;
+struct tevent_ops;
+struct tevent_fd;
+struct tevent_timer;
+struct tevent_immediate;
+struct tevent_signal;
+
+/* event handler types */
+typedef void (*tevent_fd_handler_t)(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data);
+typedef void (*tevent_fd_close_fn_t)(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ int fd,
+ void *private_data);
+typedef void (*tevent_timer_handler_t)(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data);
+typedef void (*tevent_immediate_handler_t)(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data);
+typedef void (*tevent_signal_handler_t)(struct tevent_context *ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ void *private_data);
+
+struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx);
+struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx, const char *name);
+const char **tevent_backend_list(TALLOC_CTX *mem_ctx);
+void tevent_set_default_backend(const char *backend);
+
+struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int fd,
+ uint16_t flags,
+ tevent_fd_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+#define tevent_add_fd(ev, mem_ctx, fd, flags, handler, private_data) \
+ _tevent_add_fd(ev, mem_ctx, fd, flags, handler, private_data, \
+ #handler, __location__)
+
+struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ struct timeval next_event,
+ tevent_timer_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+#define tevent_add_timer(ev, mem_ctx, next_event, handler, private_data) \
+ _tevent_add_timer(ev, mem_ctx, next_event, handler, private_data, \
+ #handler, __location__)
+
+struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
+ const char *location);
+#define tevent_create_immediate(mem_ctx) \
+ _tevent_create_immediate(mem_ctx, __location__)
+
+void _tevent_schedule_immediate(struct tevent_immediate *im,
+ struct tevent_context *ctx,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+#define tevent_schedule_immediate(im, ctx, handler, private_data) \
+ _tevent_schedule_immediate(im, ctx, handler, private_data, \
+ #handler, __location__);
+
+struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int signum,
+ int sa_flags,
+ tevent_signal_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+#define tevent_add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data) \
+ _tevent_add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data, \
+ #handler, __location__)
+
+int _tevent_loop_once(struct tevent_context *ev, const char *location);
+#define tevent_loop_once(ev) \
+ _tevent_loop_once(ev, __location__) \
+
+int _tevent_loop_wait(struct tevent_context *ev, const char *location);
+#define tevent_loop_wait(ev) \
+ _tevent_loop_wait(ev, __location__) \
+
+void tevent_fd_set_close_fn(struct tevent_fd *fde,
+ tevent_fd_close_fn_t close_fn);
+void tevent_fd_set_auto_close(struct tevent_fd *fde);
+uint16_t tevent_fd_get_flags(struct tevent_fd *fde);
+void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags);
+
+bool tevent_signal_support(struct tevent_context *ev);
+
+void tevent_set_abort_fn(void (*abort_fn)(const char *reason));
+
+/* bits for file descriptor event flags */
+#define TEVENT_FD_READ 1
+#define TEVENT_FD_WRITE 2
+
+#define TEVENT_FD_WRITEABLE(fde) \
+ tevent_fd_set_flags(fde, tevent_fd_get_flags(fde) | TEVENT_FD_WRITE)
+#define TEVENT_FD_READABLE(fde) \
+ tevent_fd_set_flags(fde, tevent_fd_get_flags(fde) | TEVENT_FD_READ)
+
+#define TEVENT_FD_NOT_WRITEABLE(fde) \
+ tevent_fd_set_flags(fde, tevent_fd_get_flags(fde) & ~TEVENT_FD_WRITE)
+#define TEVENT_FD_NOT_READABLE(fde) \
+ tevent_fd_set_flags(fde, tevent_fd_get_flags(fde) & ~TEVENT_FD_READ)
+
+/* DEBUG */
+enum tevent_debug_level {
+ TEVENT_DEBUG_FATAL,
+ TEVENT_DEBUG_ERROR,
+ TEVENT_DEBUG_WARNING,
+ TEVENT_DEBUG_TRACE
+};
+
+int tevent_set_debug(struct tevent_context *ev,
+ void (*debug)(void *context,
+ enum tevent_debug_level level,
+ const char *fmt,
+ va_list ap) PRINTF_ATTRIBUTE(3,0),
+ void *context);
+int tevent_set_debug_stderr(struct tevent_context *ev);
+
+/**
+ * An async request moves between the following 4 states:
+ */
+enum tevent_req_state {
+ /**
+ * we are creating the request
+ */
+ TEVENT_REQ_INIT,
+ /**
+ * we are waiting the request to complete
+ */
+ TEVENT_REQ_IN_PROGRESS,
+ /**
+ * the request is finished
+ */
+ TEVENT_REQ_DONE,
+ /**
+ * A user error has occured
+ */
+ TEVENT_REQ_USER_ERROR,
+ /**
+ * Request timed out
+ */
+ TEVENT_REQ_TIMED_OUT,
+ /**
+ * No memory in between
+ */
+ TEVENT_REQ_NO_MEMORY,
+ /**
+ * the request is already received by the caller
+ */
+ TEVENT_REQ_RECEIVED
+};
+
+/**
+ * @brief An async request
+ *
+ * This represents an async request being processed by callbacks via an event
+ * context. A user can issue for example a write request to a socket, giving
+ * an implementation function the fd, the buffer and the number of bytes to
+ * transfer. The function issuing the request will immediately return without
+ * blocking most likely without having sent anything. The API user then fills
+ * in req->async.fn and req->async.private_data, functions that are called
+ * when the request is finished.
+ *
+ * It is up to the user of the async request to talloc_free it after it has
+ * finished. This can happen while the completion function is called.
+ */
+
+struct tevent_req;
+
+typedef void (*tevent_req_fn)(struct tevent_req *);
+
+void tevent_req_set_callback(struct tevent_req *req, tevent_req_fn fn, void *pvt);
+void *_tevent_req_callback_data(struct tevent_req *req);
+void *_tevent_req_data(struct tevent_req *req);
+
+#define tevent_req_callback_data(_req, _type) \
+ talloc_get_type_abort(_tevent_req_callback_data(_req), _type)
+#define tevent_req_callback_data_void(_req) \
+ _tevent_req_callback_data(_req)
+#define tevent_req_data(_req, _type) \
+ talloc_get_type_abort(_tevent_req_data(_req), _type)
+
+typedef char *(*tevent_req_print_fn)(struct tevent_req *, TALLOC_CTX *);
+
+void tevent_req_set_print_fn(struct tevent_req *req, tevent_req_print_fn fn);
+
+char *tevent_req_default_print(struct tevent_req *req, TALLOC_CTX *mem_ctx);
+
+char *tevent_req_print(TALLOC_CTX *mem_ctx, struct tevent_req *req);
+
+typedef bool (*tevent_req_cancel_fn)(struct tevent_req *);
+
+void tevent_req_set_cancel_fn(struct tevent_req *req, tevent_req_cancel_fn fn);
+
+bool _tevent_req_cancel(struct tevent_req *req, const char *location);
+#define tevent_req_cancel(req) \
+ _tevent_req_cancel(req, __location__)
+
+struct tevent_req *_tevent_req_create(TALLOC_CTX *mem_ctx,
+ void *pstate,
+ size_t state_size,
+ const char *type,
+ const char *location);
+
+#define tevent_req_create(_mem_ctx, _pstate, _type) \
+ _tevent_req_create((_mem_ctx), (_pstate), sizeof(_type), \
+ #_type, __location__)
+
+bool tevent_req_set_endtime(struct tevent_req *req,
+ struct tevent_context *ev,
+ struct timeval endtime);
+
+void _tevent_req_notify_callback(struct tevent_req *req, const char *location);
+#define tevent_req_notify_callback(req) \
+ _tevent_req_notify_callback(req, __location__)
+
+void _tevent_req_done(struct tevent_req *req,
+ const char *location);
+#define tevent_req_done(req) \
+ _tevent_req_done(req, __location__)
+
+bool _tevent_req_error(struct tevent_req *req,
+ uint64_t error,
+ const char *location);
+#define tevent_req_error(req, error) \
+ _tevent_req_error(req, error, __location__)
+
+bool _tevent_req_nomem(const void *p,
+ struct tevent_req *req,
+ const char *location);
+#define tevent_req_nomem(p, req) \
+ _tevent_req_nomem(p, req, __location__)
+
+struct tevent_req *tevent_req_post(struct tevent_req *req,
+ struct tevent_context *ev);
+
+bool tevent_req_is_in_progress(struct tevent_req *req);
+
+bool tevent_req_poll(struct tevent_req *req,
+ struct tevent_context *ev);
+
+bool tevent_req_is_error(struct tevent_req *req,
+ enum tevent_req_state *state,
+ uint64_t *error);
+
+void tevent_req_received(struct tevent_req *req);
+
+struct tevent_req *tevent_wakeup_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct timeval wakeup_time);
+bool tevent_wakeup_recv(struct tevent_req *req);
+
+int tevent_timeval_compare(const struct timeval *tv1,
+ const struct timeval *tv2);
+
+struct timeval tevent_timeval_zero(void);
+
+struct timeval tevent_timeval_current(void);
+
+struct timeval tevent_timeval_set(uint32_t secs, uint32_t usecs);
+
+struct timeval tevent_timeval_until(const struct timeval *tv1,
+ const struct timeval *tv2);
+
+bool tevent_timeval_is_zero(const struct timeval *tv);
+
+struct timeval tevent_timeval_add(const struct timeval *tv, uint32_t secs,
+ uint32_t usecs);
+
+struct timeval tevent_timeval_current_ofs(uint32_t secs, uint32_t usecs);
+
+struct tevent_queue;
+
+struct tevent_queue *_tevent_queue_create(TALLOC_CTX *mem_ctx,
+ const char *name,
+ const char *location);
+
+#define tevent_queue_create(_mem_ctx, _name) \
+ _tevent_queue_create((_mem_ctx), (_name), __location__)
+
+typedef void (*tevent_queue_trigger_fn_t)(struct tevent_req *req,
+ void *private_data);
+bool tevent_queue_add(struct tevent_queue *queue,
+ struct tevent_context *ev,
+ struct tevent_req *req,
+ tevent_queue_trigger_fn_t trigger,
+ void *private_data);
+void tevent_queue_start(struct tevent_queue *queue);
+void tevent_queue_stop(struct tevent_queue *queue);
+
+size_t tevent_queue_length(struct tevent_queue *queue);
+
+typedef int (*tevent_nesting_hook)(struct tevent_context *ev,
+ void *private_data,
+ uint32_t level,
+ bool begin,
+ void *stack_ptr,
+ const char *location);
+#ifdef TEVENT_DEPRECATED
+#ifndef _DEPRECATED_
+#if (__GNUC__ >= 3) && (__GNUC_MINOR__ >= 1 )
+#define _DEPRECATED_ __attribute__ ((deprecated))
+#else
+#define _DEPRECATED_
+#endif
+#endif
+void tevent_loop_allow_nesting(struct tevent_context *ev) _DEPRECATED_;
+void tevent_loop_set_nesting_hook(struct tevent_context *ev,
+ tevent_nesting_hook hook,
+ void *private_data) _DEPRECATED_;
+int _tevent_loop_until(struct tevent_context *ev,
+ bool (*finished)(void *private_data),
+ void *private_data,
+ const char *location) _DEPRECATED_;
+#define tevent_loop_until(ev, finished, private_data) \
+ _tevent_loop_until(ev, finished, private_data, __location__)
+#endif
+
+
+/**
+ * The following structure and registration functions are exclusively
+ * needed for people writing and pluggin a different event engine.
+ * There is nothing useful for normal tevent user in here.
+ */
+
+struct tevent_ops {
+ /* context init */
+ int (*context_init)(struct tevent_context *ev);
+
+ /* fd_event functions */
+ struct tevent_fd *(*add_fd)(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int fd, uint16_t flags,
+ tevent_fd_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+ void (*set_fd_close_fn)(struct tevent_fd *fde,
+ tevent_fd_close_fn_t close_fn);
+ uint16_t (*get_fd_flags)(struct tevent_fd *fde);
+ void (*set_fd_flags)(struct tevent_fd *fde, uint16_t flags);
+
+ /* timed_event functions */
+ struct tevent_timer *(*add_timer)(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ struct timeval next_event,
+ tevent_timer_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+
+ /* immediate event functions */
+ void (*schedule_immediate)(struct tevent_immediate *im,
+ struct tevent_context *ev,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+
+ /* signal functions */
+ struct tevent_signal *(*add_signal)(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int signum, int sa_flags,
+ tevent_signal_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+
+ /* loop functions */
+ int (*loop_once)(struct tevent_context *ev, const char *location);
+ int (*loop_wait)(struct tevent_context *ev, const char *location);
+};
+
+bool tevent_register_backend(const char *name, const struct tevent_ops *ops);
+
+
+/**
+ * The following definitions are usueful only for compatibility with the
+ * implementation originally developed within the samba4 code and will be
+ * soon removed. Please NEVER use in new code.
+ */
+
+#ifdef TEVENT_COMPAT_DEFINES
+
+#define event_context tevent_context
+#define event_ops tevent_ops
+#define fd_event tevent_fd
+#define timed_event tevent_timer
+#define signal_event tevent_signal
+
+#define event_fd_handler_t tevent_fd_handler_t
+#define event_timed_handler_t tevent_timer_handler_t
+#define event_signal_handler_t tevent_signal_handler_t
+
+#define event_context_init(mem_ctx) \
+ tevent_context_init(mem_ctx)
+
+#define event_context_init_byname(mem_ctx, name) \
+ tevent_context_init_byname(mem_ctx, name)
+
+#define event_backend_list(mem_ctx) \
+ tevent_backend_list(mem_ctx)
+
+#define event_set_default_backend(backend) \
+ tevent_set_default_backend(backend)
+
+#define event_add_fd(ev, mem_ctx, fd, flags, handler, private_data) \
+ tevent_add_fd(ev, mem_ctx, fd, flags, handler, private_data)
+
+#define event_add_timed(ev, mem_ctx, next_event, handler, private_data) \
+ tevent_add_timer(ev, mem_ctx, next_event, handler, private_data)
+
+#define event_add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data) \
+ tevent_add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data)
+
+#define event_loop_once(ev) \
+ tevent_loop_once(ev)
+
+#define event_loop_wait(ev) \
+ tevent_loop_wait(ev)
+
+#define event_get_fd_flags(fde) \
+ tevent_fd_get_flags(fde)
+
+#define event_set_fd_flags(fde, flags) \
+ tevent_fd_set_flags(fde, flags)
+
+#define EVENT_FD_READ TEVENT_FD_READ
+#define EVENT_FD_WRITE TEVENT_FD_WRITE
+
+#define EVENT_FD_WRITEABLE(fde) \
+ TEVENT_FD_WRITEABLE(fde)
+
+#define EVENT_FD_READABLE(fde) \
+ TEVENT_FD_READABLE(fde)
+
+#define EVENT_FD_NOT_WRITEABLE(fde) \
+ TEVENT_FD_NOT_WRITEABLE(fde)
+
+#define EVENT_FD_NOT_READABLE(fde) \
+ TEVENT_FD_NOT_READABLE(fde)
+
+#define ev_debug_level tevent_debug_level
+
+#define EV_DEBUG_FATAL TEVENT_DEBUG_FATAL
+#define EV_DEBUG_ERROR TEVENT_DEBUG_ERROR
+#define EV_DEBUG_WARNING TEVENT_DEBUG_WARNING
+#define EV_DEBUG_TRACE TEVENT_DEBUG_TRACE
+
+#define ev_set_debug(ev, debug, context) \
+ tevent_set_debug(ev, debug, context)
+
+#define ev_set_debug_stderr(_ev) tevent_set_debug_stderr(ev)
+
+#endif /* TEVENT_COMPAT_DEFINES */
+
+#endif /* __TEVENT_H__ */
#endif
#define STRCMP(a,b,c) (strcmp(a,c) b 0)
+#define ZERO_STRUCT(a) memset(&(a), 0, sizeof(a))
#ifdef WITH_SENDFILE
extern ssize_t sys_sendfile (int __out_fd, int __in_fd, off_t *__offset,size_t __count);
# Makefile.am for libatalk/
-SUBDIRS = acl adouble bstring compat cnid dsi talloc tdb util unicode vfs
+SUBDIRS = acl adouble bstring compat cnid dsi talloc tdb tevent util unicode vfs
lib_LTLIBRARIES = libatalk.la
--- /dev/null
+Makefile
+Makefile.in
+*.lo
+*.la
+.deps
+.libs
+*.o
--- /dev/null
+Makefile
+Makefile.in
+*.lo
+*.la
+.deps
+.libs
+*.o
--- /dev/null
+# Makefile.am for libatalk/tevent/
+
+noinst_LTLIBRARIES = libtevent.la
+
+AM_CFLAGS =
+
+libtevent_la_SOURCES = \
+ tevent.c \
+ tevent_debug.c \
+ tevent_epoll.c \
+ tevent_fd.c \
+ tevent_immediate.c \
+ tevent_queue.c \
+ tevent_req.c \
+ tevent_select.c \
+ tevent_signal.c \
+ tevent_standard.c \
+ tevent_timed.c \
+ tevent_util.c \
+ tevent_wakeup.c
+
+noinst_HEADERS = \
+ tevent_internal.h \
+ tevent_util.h
\ No newline at end of file
--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+ main select loop and event handling
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Stefan Metzmacher 2009
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ PLEASE READ THIS BEFORE MODIFYING!
+
+ This module is a general abstraction for the main select loop and
+ event handling. Do not ever put any localised hacks in here, instead
+ register one of the possible event types and implement that event
+ somewhere else.
+
+ There are 2 types of event handling that are handled in this module:
+
+ 1) a file descriptor becoming readable or writeable. This is mostly
+ used for network sockets, but can be used for any type of file
+ descriptor. You may only register one handler for each file
+ descriptor/io combination or you will get unpredictable results
+ (this means that you can have a handler for read events, and a
+ separate handler for write events, but not two handlers that are
+ both handling read events)
+
+ 2) a timed event. You can register an event that happens at a
+ specific time. You can register as many of these as you
+ like. They are single shot - add a new timed event in the event
+ handler to get another event.
+
+ To setup a set of events you first need to create a event_context
+ structure using the function tevent_context_init(); This returns a
+ 'struct tevent_context' that you use in all subsequent calls.
+
+ After that you can add/remove events that you are interested in
+ using tevent_add_*() and talloc_free()
+
+ Finally, you call tevent_loop_wait_once() to block waiting for one of the
+ events to occor or tevent_loop_wait() which will loop
+ forever.
+
+*/
+#define TEVENT_DEPRECATED 1
+
+#include <atalk/tevent.h>
+
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+struct tevent_ops_list {
+ struct tevent_ops_list *next, *prev;
+ const char *name;
+ const struct tevent_ops *ops;
+};
+
+/* list of registered event backends */
+static struct tevent_ops_list *tevent_backends = NULL;
+static char *tevent_default_backend = NULL;
+
+/*
+ register an events backend
+*/
+bool tevent_register_backend(const char *name, const struct tevent_ops *ops)
+{
+ struct tevent_ops_list *e;
+
+ for (e = tevent_backends; e != NULL; e = e->next) {
+ if (0 == strcmp(e->name, name)) {
+ /* already registered, skip it */
+ return true;
+ }
+ }
+
+ e = talloc(talloc_autofree_context(), struct tevent_ops_list);
+ if (e == NULL) return false;
+
+ e->name = name;
+ e->ops = ops;
+ DLIST_ADD(tevent_backends, e);
+
+ return true;
+}
+
+/*
+ set the default event backend
+ */
+void tevent_set_default_backend(const char *backend)
+{
+ talloc_free(tevent_default_backend);
+ tevent_default_backend = talloc_strdup(talloc_autofree_context(),
+ backend);
+}
+
+/*
+ initialise backends if not already done
+*/
+static void tevent_backend_init(void)
+{
+ tevent_select_init();
+ tevent_standard_init();
+#ifdef HAVE_EPOLL
+ tevent_epoll_init();
+#endif
+}
+
+/*
+ list available backends
+*/
+const char **tevent_backend_list(TALLOC_CTX *mem_ctx)
+{
+ const char **list = NULL;
+ struct tevent_ops_list *e;
+
+ tevent_backend_init();
+
+ for (e=tevent_backends;e;e=e->next) {
+ list = ev_str_list_add(list, e->name);
+ }
+
+ talloc_steal(mem_ctx, list);
+
+ return list;
+}
+
+int tevent_common_context_destructor(struct tevent_context *ev)
+{
+ struct tevent_fd *fd, *fn;
+ struct tevent_timer *te, *tn;
+ struct tevent_immediate *ie, *in;
+ struct tevent_signal *se, *sn;
+
+ if (ev->pipe_fde) {
+ talloc_free(ev->pipe_fde);
+ close(ev->pipe_fds[0]);
+ close(ev->pipe_fds[1]);
+ ev->pipe_fde = NULL;
+ }
+
+ for (fd = ev->fd_events; fd; fd = fn) {
+ fn = fd->next;
+ fd->event_ctx = NULL;
+ DLIST_REMOVE(ev->fd_events, fd);
+ }
+
+ for (te = ev->timer_events; te; te = tn) {
+ tn = te->next;
+ te->event_ctx = NULL;
+ DLIST_REMOVE(ev->timer_events, te);
+ }
+
+ for (ie = ev->immediate_events; ie; ie = in) {
+ in = ie->next;
+ ie->event_ctx = NULL;
+ ie->cancel_fn = NULL;
+ DLIST_REMOVE(ev->immediate_events, ie);
+ }
+
+ for (se = ev->signal_events; se; se = sn) {
+ sn = se->next;
+ se->event_ctx = NULL;
+ DLIST_REMOVE(ev->signal_events, se);
+ /*
+ * This is important, Otherwise signals
+ * are handled twice in child. eg, SIGHUP.
+ * one added in parent, and another one in
+ * the child. -- BoYang
+ */
+ tevent_cleanup_pending_signal_handlers(se);
+ }
+
+ return 0;
+}
+
+/*
+ create a event_context structure for a specific implemementation.
+ This must be the first events call, and all subsequent calls pass
+ this event_context as the first element. Event handlers also
+ receive this as their first argument.
+
+ This function is for allowing third-party-applications to hook in gluecode
+ to their own event loop code, so that they can make async usage of our client libs
+
+ NOTE: use tevent_context_init() inside of samba!
+*/
+static struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
+ const struct tevent_ops *ops)
+{
+ struct tevent_context *ev;
+ int ret;
+
+ ev = talloc_zero(mem_ctx, struct tevent_context);
+ if (!ev) return NULL;
+
+ talloc_set_destructor(ev, tevent_common_context_destructor);
+
+ ev->ops = ops;
+
+ ret = ev->ops->context_init(ev);
+ if (ret != 0) {
+ talloc_free(ev);
+ return NULL;
+ }
+
+ return ev;
+}
+
+/*
+ create a event_context structure. This must be the first events
+ call, and all subsequent calls pass this event_context as the first
+ element. Event handlers also receive this as their first argument.
+*/
+struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
+ const char *name)
+{
+ struct tevent_ops_list *e;
+
+ tevent_backend_init();
+
+ if (name == NULL) {
+ name = tevent_default_backend;
+ }
+ if (name == NULL) {
+ name = "standard";
+ }
+
+ for (e=tevent_backends;e;e=e->next) {
+ if (strcmp(name, e->name) == 0) {
+ return tevent_context_init_ops(mem_ctx, e->ops);
+ }
+ }
+ return NULL;
+}
+
+
+/*
+ create a event_context structure. This must be the first events
+ call, and all subsequent calls pass this event_context as the first
+ element. Event handlers also receive this as their first argument.
+*/
+struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
+{
+ return tevent_context_init_byname(mem_ctx, NULL);
+}
+
+/*
+ add a fd based event
+ return NULL on failure (memory allocation error)
+
+ if flags contains TEVENT_FD_AUTOCLOSE then the fd will be closed when
+ the returned fd_event context is freed
+*/
+struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int fd,
+ uint16_t flags,
+ tevent_fd_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
+ handler_name, location);
+}
+
+/*
+ set a close function on the fd event
+*/
+void tevent_fd_set_close_fn(struct tevent_fd *fde,
+ tevent_fd_close_fn_t close_fn)
+{
+ if (!fde) return;
+ if (!fde->event_ctx) return;
+ fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
+}
+
+static void tevent_fd_auto_close_fn(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ int fd,
+ void *private_data)
+{
+ close(fd);
+}
+
+void tevent_fd_set_auto_close(struct tevent_fd *fde)
+{
+ tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
+}
+
+/*
+ return the fd event flags
+*/
+uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
+{
+ if (!fde) return 0;
+ if (!fde->event_ctx) return 0;
+ return fde->event_ctx->ops->get_fd_flags(fde);
+}
+
+/*
+ set the fd event flags
+*/
+void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
+{
+ if (!fde) return;
+ if (!fde->event_ctx) return;
+ fde->event_ctx->ops->set_fd_flags(fde, flags);
+}
+
+bool tevent_signal_support(struct tevent_context *ev)
+{
+ if (ev->ops->add_signal) {
+ return true;
+ }
+ return false;
+}
+
+static void (*tevent_abort_fn)(const char *reason);
+
+void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
+{
+ tevent_abort_fn = abort_fn;
+}
+
+static void tevent_abort(struct tevent_context *ev, const char *reason)
+{
+ tevent_debug(ev, TEVENT_DEBUG_FATAL,
+ "abort: %s\n", reason);
+
+ if (!tevent_abort_fn) {
+ abort();
+ }
+
+ tevent_abort_fn(reason);
+}
+
+/*
+ add a timer event
+ return NULL on failure
+*/
+struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ struct timeval next_event,
+ tevent_timer_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
+ handler_name, location);
+}
+
+/*
+ allocate an immediate event
+ return NULL on failure (memory allocation error)
+*/
+struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
+ const char *location)
+{
+ struct tevent_immediate *im;
+
+ im = talloc(mem_ctx, struct tevent_immediate);
+ if (im == NULL) return NULL;
+
+ im->prev = NULL;
+ im->next = NULL;
+ im->event_ctx = NULL;
+ im->create_location = location;
+ im->handler = NULL;
+ im->private_data = NULL;
+ im->handler_name = NULL;
+ im->schedule_location = NULL;
+ im->cancel_fn = NULL;
+ im->additional_data = NULL;
+
+ return im;
+}
+
+/*
+ schedule an immediate event
+ return NULL on failure
+*/
+void _tevent_schedule_immediate(struct tevent_immediate *im,
+ struct tevent_context *ev,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ ev->ops->schedule_immediate(im, ev, handler, private_data,
+ handler_name, location);
+}
+
+/*
+ add a signal event
+
+ sa_flags are flags to sigaction(2)
+
+ return NULL on failure
+*/
+struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int signum,
+ int sa_flags,
+ tevent_signal_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
+ handler_name, location);
+}
+
+void tevent_loop_allow_nesting(struct tevent_context *ev)
+{
+ ev->nesting.allowed = true;
+}
+
+void tevent_loop_set_nesting_hook(struct tevent_context *ev,
+ tevent_nesting_hook hook,
+ void *private_data)
+{
+ if (ev->nesting.hook_fn &&
+ (ev->nesting.hook_fn != hook ||
+ ev->nesting.hook_private != private_data)) {
+ /* the way the nesting hook code is currently written
+ we cannot support two different nesting hooks at the
+ same time. */
+ tevent_abort(ev, "tevent: Violation of nesting hook rules\n");
+ }
+ ev->nesting.hook_fn = hook;
+ ev->nesting.hook_private = private_data;
+}
+
+static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
+{
+ const char *reason;
+
+ reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
+ location);
+ if (!reason) {
+ reason = "tevent_loop_once() nesting";
+ }
+
+ tevent_abort(ev, reason);
+}
+
+/*
+ do a single event loop using the events defined in ev
+*/
+int _tevent_loop_once(struct tevent_context *ev, const char *location)
+{
+ int ret;
+ void *nesting_stack_ptr = NULL;
+
+ ev->nesting.level++;
+
+ if (ev->nesting.level > 1) {
+ if (!ev->nesting.allowed) {
+ tevent_abort_nesting(ev, location);
+ errno = ELOOP;
+ return -1;
+ }
+ }
+ if (ev->nesting.level > 0) {
+ if (ev->nesting.hook_fn) {
+ int ret2;
+ ret2 = ev->nesting.hook_fn(ev,
+ ev->nesting.hook_private,
+ ev->nesting.level,
+ true,
+ (void *)&nesting_stack_ptr,
+ location);
+ if (ret2 != 0) {
+ ret = ret2;
+ goto done;
+ }
+ }
+ }
+
+ ret = ev->ops->loop_once(ev, location);
+
+ if (ev->nesting.level > 0) {
+ if (ev->nesting.hook_fn) {
+ int ret2;
+ ret2 = ev->nesting.hook_fn(ev,
+ ev->nesting.hook_private,
+ ev->nesting.level,
+ false,
+ (void *)&nesting_stack_ptr,
+ location);
+ if (ret2 != 0) {
+ ret = ret2;
+ goto done;
+ }
+ }
+ }
+
+done:
+ ev->nesting.level--;
+ return ret;
+}
+
+/*
+ this is a performance optimization for the samba4 nested event loop problems
+*/
+int _tevent_loop_until(struct tevent_context *ev,
+ bool (*finished)(void *private_data),
+ void *private_data,
+ const char *location)
+{
+ int ret = 0;
+ void *nesting_stack_ptr = NULL;
+
+ ev->nesting.level++;
+
+ if (ev->nesting.level > 1) {
+ if (!ev->nesting.allowed) {
+ tevent_abort_nesting(ev, location);
+ errno = ELOOP;
+ return -1;
+ }
+ }
+ if (ev->nesting.level > 0) {
+ if (ev->nesting.hook_fn) {
+ int ret2;
+ ret2 = ev->nesting.hook_fn(ev,
+ ev->nesting.hook_private,
+ ev->nesting.level,
+ true,
+ (void *)&nesting_stack_ptr,
+ location);
+ if (ret2 != 0) {
+ ret = ret2;
+ goto done;
+ }
+ }
+ }
+
+ while (!finished(private_data)) {
+ ret = ev->ops->loop_once(ev, location);
+ if (ret != 0) {
+ break;
+ }
+ }
+
+ if (ev->nesting.level > 0) {
+ if (ev->nesting.hook_fn) {
+ int ret2;
+ ret2 = ev->nesting.hook_fn(ev,
+ ev->nesting.hook_private,
+ ev->nesting.level,
+ false,
+ (void *)&nesting_stack_ptr,
+ location);
+ if (ret2 != 0) {
+ ret = ret2;
+ goto done;
+ }
+ }
+ }
+
+done:
+ ev->nesting.level--;
+ return ret;
+}
+
+/*
+ return on failure or (with 0) if all fd events are removed
+*/
+int tevent_common_loop_wait(struct tevent_context *ev,
+ const char *location)
+{
+ /*
+ * loop as long as we have events pending
+ */
+ while (ev->fd_events ||
+ ev->timer_events ||
+ ev->immediate_events ||
+ ev->signal_events) {
+ int ret;
+ ret = _tevent_loop_once(ev, location);
+ if (ret != 0) {
+ tevent_debug(ev, TEVENT_DEBUG_FATAL,
+ "_tevent_loop_once() failed: %d - %s\n",
+ ret, strerror(errno));
+ return ret;
+ }
+ }
+
+ tevent_debug(ev, TEVENT_DEBUG_WARNING,
+ "tevent_common_loop_wait() out of events\n");
+ return 0;
+}
+
+/*
+ return on failure or (with 0) if all fd events are removed
+*/
+int _tevent_loop_wait(struct tevent_context *ev, const char *location)
+{
+ return ev->ops->loop_wait(ev, location);
+}
--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Jelmer Vernooij 2005
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <atalk/tevent.h>
+#include "tevent_internal.h"
+
+/********************************************************************
+ * Debug wrapper functions, modeled (with lot's of code copied as is)
+ * after the ev debug wrapper functions
+ ********************************************************************/
+
+/*
+ this allows the user to choose their own debug function
+*/
+int tevent_set_debug(struct tevent_context *ev,
+ void (*debug)(void *context,
+ enum tevent_debug_level level,
+ const char *fmt,
+ va_list ap) PRINTF_ATTRIBUTE(3,0),
+ void *context)
+{
+ ev->debug_ops.debug = debug;
+ ev->debug_ops.context = context;
+ return 0;
+}
+
+/*
+ debug function for ev_set_debug_stderr
+*/
+static void tevent_debug_stderr(void *private_data,
+ enum tevent_debug_level level,
+ const char *fmt,
+ va_list ap) PRINTF_ATTRIBUTE(3,0);
+static void tevent_debug_stderr(void *private_data,
+ enum tevent_debug_level level,
+ const char *fmt, va_list ap)
+{
+ if (level <= TEVENT_DEBUG_WARNING) {
+ vfprintf(stderr, fmt, ap);
+ }
+}
+
+/*
+ convenience function to setup debug messages on stderr
+ messages of level TEVENT_DEBUG_WARNING and higher are printed
+*/
+int tevent_set_debug_stderr(struct tevent_context *ev)
+{
+ return tevent_set_debug(ev, tevent_debug_stderr, ev);
+}
+
+/*
+ * log a message
+ *
+ * The default debug action is to ignore debugging messages.
+ * This is the most appropriate action for a library.
+ * Applications using the library must decide where to
+ * redirect debugging messages
+*/
+void tevent_debug(struct tevent_context *ev, enum tevent_debug_level level,
+ const char *fmt, ...)
+{
+ va_list ap;
+ if (!ev) {
+ return;
+ }
+ if (ev->debug_ops.debug == NULL) {
+ return;
+ }
+ va_start(ap, fmt);
+ ev->debug_ops.debug(ev->debug_ops.context, level, fmt, ap);
+ va_end(ap);
+}
+
--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+
+ main select loop and event handling - epoll implementation
+
+ Copyright (C) Andrew Tridgell 2003-2005
+ Copyright (C) Stefan Metzmacher 2005-2009
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <atalk/tevent.h>
+#include <atalk/util.h>
+
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+struct epoll_event_context {
+ /* a pointer back to the generic event_context */
+ struct tevent_context *ev;
+
+ /* when using epoll this is the handle from epoll_create */
+ int epoll_fd;
+
+ pid_t pid;
+};
+
+/*
+ called when a epoll call fails, and we should fallback
+ to using select
+*/
+static void epoll_panic(struct epoll_event_context *epoll_ev, const char *reason)
+{
+ tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
+ "%s (%s) - calling abort()\n", reason, strerror(errno));
+ abort();
+}
+
+/*
+ map from TEVENT_FD_* to EPOLLIN/EPOLLOUT
+*/
+static uint32_t epoll_map_flags(uint16_t flags)
+{
+ uint32_t ret = 0;
+ if (flags & TEVENT_FD_READ) ret |= (EPOLLIN | EPOLLERR | EPOLLHUP);
+ if (flags & TEVENT_FD_WRITE) ret |= (EPOLLOUT | EPOLLERR | EPOLLHUP);
+ return ret;
+}
+
+/*
+ free the epoll fd
+*/
+static int epoll_ctx_destructor(struct epoll_event_context *epoll_ev)
+{
+ close(epoll_ev->epoll_fd);
+ epoll_ev->epoll_fd = -1;
+ return 0;
+}
+
+/*
+ init the epoll fd
+*/
+static int epoll_init_ctx(struct epoll_event_context *epoll_ev)
+{
+ epoll_ev->epoll_fd = epoll_create(64);
+ epoll_ev->pid = getpid();
+ talloc_set_destructor(epoll_ev, epoll_ctx_destructor);
+ if (epoll_ev->epoll_fd == -1) {
+ return -1;
+ }
+ return 0;
+}
+
+static void epoll_add_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde);
+
+/*
+ reopen the epoll handle when our pid changes
+ see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an
+ demonstration of why this is needed
+ */
+static void epoll_check_reopen(struct epoll_event_context *epoll_ev)
+{
+ struct tevent_fd *fde;
+
+ if (epoll_ev->pid == getpid()) {
+ return;
+ }
+
+ close(epoll_ev->epoll_fd);
+ epoll_ev->epoll_fd = epoll_create(64);
+ if (epoll_ev->epoll_fd == -1) {
+ tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
+ "Failed to recreate epoll handle after fork\n");
+ return;
+ }
+ epoll_ev->pid = getpid();
+ for (fde=epoll_ev->ev->fd_events;fde;fde=fde->next) {
+ epoll_add_event(epoll_ev, fde);
+ }
+}
+
+#define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT (1<<0)
+#define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR (1<<1)
+#define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR (1<<2)
+
+/*
+ add the epoll event to the given fd_event
+*/
+static void epoll_add_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
+{
+ struct epoll_event event;
+
+ if (epoll_ev->epoll_fd == -1) return;
+
+ fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+
+ /* if we don't want events yet, don't add an epoll_event */
+ if (fde->flags == 0) return;
+
+ ZERO_STRUCT(event);
+ event.events = epoll_map_flags(fde->flags);
+ event.data.ptr = fde;
+ if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event) != 0) {
+ epoll_panic(epoll_ev, "EPOLL_CTL_ADD failed");
+ }
+ fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+
+ /* only if we want to read we want to tell the event handler about errors */
+ if (fde->flags & TEVENT_FD_READ) {
+ fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+ }
+}
+
+/*
+ delete the epoll event for given fd_event
+*/
+static void epoll_del_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
+{
+ struct epoll_event event;
+
+ if (epoll_ev->epoll_fd == -1) return;
+
+ fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+
+ /* if there's no epoll_event, we don't need to delete it */
+ if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) return;
+
+ ZERO_STRUCT(event);
+ event.events = epoll_map_flags(fde->flags);
+ event.data.ptr = fde;
+ if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event) != 0) {
+ tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
+ "epoll_del_event failed! probable early close bug (%s)\n",
+ strerror(errno));
+ }
+ fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+}
+
+/*
+ change the epoll event to the given fd_event
+*/
+static void epoll_mod_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
+{
+ struct epoll_event event;
+ if (epoll_ev->epoll_fd == -1) return;
+
+ fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+
+ ZERO_STRUCT(event);
+ event.events = epoll_map_flags(fde->flags);
+ event.data.ptr = fde;
+ if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) {
+ epoll_panic(epoll_ev, "EPOLL_CTL_MOD failed");
+ }
+
+ /* only if we want to read we want to tell the event handler about errors */
+ if (fde->flags & TEVENT_FD_READ) {
+ fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+ }
+}
+
+static void epoll_change_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
+{
+ bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
+ bool want_read = (fde->flags & TEVENT_FD_READ);
+ bool want_write= (fde->flags & TEVENT_FD_WRITE);
+
+ if (epoll_ev->epoll_fd == -1) return;
+
+ fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+
+ /* there's already an event */
+ if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) {
+ if (want_read || (want_write && !got_error)) {
+ epoll_mod_event(epoll_ev, fde);
+ return;
+ }
+ /*
+ * if we want to match the select behavior, we need to remove the epoll_event
+ * when the caller isn't interested in events.
+ *
+ * this is because epoll reports EPOLLERR and EPOLLHUP, even without asking for them
+ */
+ epoll_del_event(epoll_ev, fde);
+ return;
+ }
+
+ /* there's no epoll_event attached to the fde */
+ if (want_read || (want_write && !got_error)) {
+ epoll_add_event(epoll_ev, fde);
+ return;
+ }
+}
+
+/*
+ event loop handling using epoll
+*/
+static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval *tvalp)
+{
+ int ret, i;
+#define MAXEVENTS 1
+ struct epoll_event events[MAXEVENTS];
+ int timeout = -1;
+
+ if (epoll_ev->epoll_fd == -1) return -1;
+
+ if (tvalp) {
+ /* it's better to trigger timed events a bit later than to early */
+ timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000);
+ }
+
+ if (epoll_ev->ev->signal_events &&
+ tevent_common_check_signal(epoll_ev->ev)) {
+ return 0;
+ }
+
+ ret = epoll_wait(epoll_ev->epoll_fd, events, MAXEVENTS, timeout);
+
+ if (ret == -1 && errno == EINTR && epoll_ev->ev->signal_events) {
+ if (tevent_common_check_signal(epoll_ev->ev)) {
+ return 0;
+ }
+ }
+
+ if (ret == -1 && errno != EINTR) {
+ epoll_panic(epoll_ev, "epoll_wait() failed");
+ return -1;
+ }
+
+ if (ret == 0 && tvalp) {
+ /* we don't care about a possible delay here */
+ tevent_common_loop_timer_delay(epoll_ev->ev);
+ return 0;
+ }
+
+ for (i=0;i<ret;i++) {
+ struct tevent_fd *fde = talloc_get_type(events[i].data.ptr,
+ struct tevent_fd);
+ uint16_t flags = 0;
+
+ if (fde == NULL) {
+ epoll_panic(epoll_ev, "epoll_wait() gave bad data");
+ return -1;
+ }
+ if (events[i].events & (EPOLLHUP|EPOLLERR)) {
+ fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
+ /*
+ * if we only wait for TEVENT_FD_WRITE, we should not tell the
+ * event handler about it, and remove the epoll_event,
+ * as we only report errors when waiting for read events,
+ * to match the select() behavior
+ */
+ if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) {
+ epoll_del_event(epoll_ev, fde);
+ continue;
+ }
+ flags |= TEVENT_FD_READ;
+ }
+ if (events[i].events & EPOLLIN) flags |= TEVENT_FD_READ;
+ if (events[i].events & EPOLLOUT) flags |= TEVENT_FD_WRITE;
+ if (flags) {
+ fde->handler(epoll_ev->ev, fde, flags, fde->private_data);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ create a epoll_event_context structure.
+*/
+static int epoll_event_context_init(struct tevent_context *ev)
+{
+ int ret;
+ struct epoll_event_context *epoll_ev;
+
+ epoll_ev = talloc_zero(ev, struct epoll_event_context);
+ if (!epoll_ev) return -1;
+ epoll_ev->ev = ev;
+ epoll_ev->epoll_fd = -1;
+
+ ret = epoll_init_ctx(epoll_ev);
+ if (ret != 0) {
+ talloc_free(epoll_ev);
+ return ret;
+ }
+
+ ev->additional_data = epoll_ev;
+ return 0;
+}
+
+/*
+ destroy an fd_event
+*/
+static int epoll_event_fd_destructor(struct tevent_fd *fde)
+{
+ struct tevent_context *ev = fde->event_ctx;
+ struct epoll_event_context *epoll_ev = NULL;
+
+ if (ev) {
+ epoll_ev = talloc_get_type(ev->additional_data,
+ struct epoll_event_context);
+
+ epoll_check_reopen(epoll_ev);
+
+ epoll_del_event(epoll_ev, fde);
+ }
+
+ return tevent_common_fd_destructor(fde);
+}
+
+/*
+ add a fd based event
+ return NULL on failure (memory allocation error)
+*/
+static struct tevent_fd *epoll_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
+ int fd, uint16_t flags,
+ tevent_fd_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
+ struct epoll_event_context);
+ struct tevent_fd *fde;
+
+ epoll_check_reopen(epoll_ev);
+
+ fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
+ handler, private_data,
+ handler_name, location);
+ if (!fde) return NULL;
+
+ talloc_set_destructor(fde, epoll_event_fd_destructor);
+
+ epoll_add_event(epoll_ev, fde);
+
+ return fde;
+}
+
+/*
+ set the fd event flags
+*/
+static void epoll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
+{
+ struct tevent_context *ev;
+ struct epoll_event_context *epoll_ev;
+
+ if (fde->flags == flags) return;
+
+ ev = fde->event_ctx;
+ epoll_ev = talloc_get_type(ev->additional_data, struct epoll_event_context);
+
+ fde->flags = flags;
+
+ epoll_check_reopen(epoll_ev);
+
+ epoll_change_event(epoll_ev, fde);
+}
+
+/*
+ do a single event loop using the events defined in ev
+*/
+static int epoll_event_loop_once(struct tevent_context *ev, const char *location)
+{
+ struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
+ struct epoll_event_context);
+ struct timeval tval;
+
+ if (ev->signal_events &&
+ tevent_common_check_signal(ev)) {
+ return 0;
+ }
+
+ if (ev->immediate_events &&
+ tevent_common_loop_immediate(ev)) {
+ return 0;
+ }
+
+ tval = tevent_common_loop_timer_delay(ev);
+ if (tevent_timeval_is_zero(&tval)) {
+ return 0;
+ }
+
+ epoll_check_reopen(epoll_ev);
+
+ return epoll_event_loop(epoll_ev, &tval);
+}
+
+static const struct tevent_ops epoll_event_ops = {
+ .context_init = epoll_event_context_init,
+ .add_fd = epoll_event_add_fd,
+ .set_fd_close_fn = tevent_common_fd_set_close_fn,
+ .get_fd_flags = tevent_common_fd_get_flags,
+ .set_fd_flags = epoll_event_set_fd_flags,
+ .add_timer = tevent_common_add_timer,
+ .schedule_immediate = tevent_common_schedule_immediate,
+ .add_signal = tevent_common_add_signal,
+ .loop_once = epoll_event_loop_once,
+ .loop_wait = tevent_common_loop_wait,
+};
+
+bool tevent_epoll_init(void)
+{
+ return tevent_register_backend("epoll", &epoll_event_ops);
+}
--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+
+ common events code for fd events
+
+ Copyright (C) Stefan Metzmacher 2009
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <atalk/tevent.h>
+
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+int tevent_common_fd_destructor(struct tevent_fd *fde)
+{
+ if (fde->event_ctx) {
+ DLIST_REMOVE(fde->event_ctx->fd_events, fde);
+ }
+
+ if (fde->close_fn) {
+ fde->close_fn(fde->event_ctx, fde, fde->fd, fde->private_data);
+ fde->fd = -1;
+ }
+
+ return 0;
+}
+
+struct tevent_fd *tevent_common_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
+ int fd, uint16_t flags,
+ tevent_fd_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ struct tevent_fd *fde;
+
+ fde = talloc(mem_ctx?mem_ctx:ev, struct tevent_fd);
+ if (!fde) return NULL;
+
+ fde->event_ctx = ev;
+ fde->fd = fd;
+ fde->flags = flags;
+ fde->handler = handler;
+ fde->close_fn = NULL;
+ fde->private_data = private_data;
+ fde->handler_name = handler_name;
+ fde->location = location;
+ fde->additional_flags = 0;
+ fde->additional_data = NULL;
+
+ DLIST_ADD(ev->fd_events, fde);
+
+ talloc_set_destructor(fde, tevent_common_fd_destructor);
+
+ return fde;
+}
+uint16_t tevent_common_fd_get_flags(struct tevent_fd *fde)
+{
+ return fde->flags;
+}
+
+void tevent_common_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
+{
+ if (fde->flags == flags) return;
+ fde->flags = flags;
+}
+
+void tevent_common_fd_set_close_fn(struct tevent_fd *fde,
+ tevent_fd_close_fn_t close_fn)
+{
+ fde->close_fn = close_fn;
+}
--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+
+ common events code for immediate events
+
+ Copyright (C) Stefan Metzmacher 2009
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <atalk/tevent.h>
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+static void tevent_common_immediate_cancel(struct tevent_immediate *im)
+{
+ if (!im->event_ctx) {
+ return;
+ }
+
+ tevent_debug(im->event_ctx, TEVENT_DEBUG_TRACE,
+ "Cancel immediate event %p \"%s\"\n",
+ im, im->handler_name);
+
+ /* let the backend free im->additional_data */
+ if (im->cancel_fn) {
+ im->cancel_fn(im);
+ }
+
+ DLIST_REMOVE(im->event_ctx->immediate_events, im);
+ im->event_ctx = NULL;
+ im->handler = NULL;
+ im->private_data = NULL;
+ im->handler_name = NULL;
+ im->schedule_location = NULL;
+ im->cancel_fn = NULL;
+ im->additional_data = NULL;
+
+ talloc_set_destructor(im, NULL);
+}
+
+/*
+ destroy an immediate event
+*/
+static int tevent_common_immediate_destructor(struct tevent_immediate *im)
+{
+ tevent_common_immediate_cancel(im);
+ return 0;
+}
+
+/*
+ * schedule an immediate event on
+ */
+void tevent_common_schedule_immediate(struct tevent_immediate *im,
+ struct tevent_context *ev,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ tevent_common_immediate_cancel(im);
+
+ if (!handler) {
+ return;
+ }
+
+ im->event_ctx = ev;
+ im->handler = handler;
+ im->private_data = private_data;
+ im->handler_name = handler_name;
+ im->schedule_location = location;
+ im->cancel_fn = NULL;
+ im->additional_data = NULL;
+
+ DLIST_ADD_END(ev->immediate_events, im, struct tevent_immediate *);
+ talloc_set_destructor(im, tevent_common_immediate_destructor);
+
+ tevent_debug(ev, TEVENT_DEBUG_TRACE,
+ "Schedule immediate event \"%s\": %p\n",
+ handler_name, im);
+}
+
+/*
+ trigger the first immediate event and return true
+ if no event was triggered return false
+*/
+bool tevent_common_loop_immediate(struct tevent_context *ev)
+{
+ struct tevent_immediate *im = ev->immediate_events;
+ tevent_immediate_handler_t handler;
+ void *private_data;
+
+ if (!im) {
+ return false;
+ }
+
+ tevent_debug(ev, TEVENT_DEBUG_TRACE,
+ "Run immediate event \"%s\": %p\n",
+ im->handler_name, im);
+
+ /*
+ * remember the handler and then clear the event
+ * the handler might reschedule the event
+ */
+ handler = im->handler;
+ private_data = im->private_data;
+
+ DLIST_REMOVE(im->event_ctx->immediate_events, im);
+ im->event_ctx = NULL;
+ im->handler = NULL;
+ im->private_data = NULL;
+ im->handler_name = NULL;
+ im->schedule_location = NULL;
+ im->cancel_fn = NULL;
+ im->additional_data = NULL;
+
+ talloc_set_destructor(im, NULL);
+
+ handler(ev, im, private_data);
+
+ return true;
+}
+
--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+
+ generalised event loop handling
+
+ INTERNAL STRUCTS. THERE ARE NO API GUARANTEES.
+ External users should only ever have to include this header when
+ implementing new tevent backends.
+
+ Copyright (C) Stefan Metzmacher 2005-2009
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+struct tevent_req {
+ /**
+ * @brief What to do on completion
+ *
+ * This is used for the user of an async request, fn is called when
+ * the request completes, either successfully or with an error.
+ */
+ struct {
+ /**
+ * @brief Completion function
+ * Completion function, to be filled by the API user
+ */
+ tevent_req_fn fn;
+ /**
+ * @brief Private data for the completion function
+ */
+ void *private_data;
+ } async;
+
+ /**
+ * @brief Private state pointer for the actual implementation
+ *
+ * The implementation doing the work for the async request needs to
+ * keep around current data like for example a fd event. The user of
+ * an async request should not touch this.
+ */
+ void *data;
+
+ /**
+ * @brief A function to overwrite the default print function
+ *
+ * The implementation doing the work may want to implement a
+ * custom function to print the text representation of the async
+ * request.
+ */
+ tevent_req_print_fn private_print;
+
+ /**
+ * @brief A function to cancel the request
+ *
+ * The implementation might want to set a function
+ * that is called when the tevent_req_cancel() function
+ * was called.
+ */
+ tevent_req_cancel_fn private_cancel;
+
+ /**
+ * @brief Internal state of the request
+ *
+ * Callers should only access this via functions and never directly.
+ */
+ struct {
+ /**
+ * @brief The talloc type of the data pointer
+ *
+ * This is filled by the tevent_req_create() macro.
+ *
+ * This for debugging only.
+ */
+ const char *private_type;
+
+ /**
+ * @brief The location where the request was created
+ *
+ * This uses the __location__ macro via the tevent_req_create()
+ * macro.
+ *
+ * This for debugging only.
+ */
+ const char *create_location;
+
+ /**
+ * @brief The location where the request was finished
+ *
+ * This uses the __location__ macro via the tevent_req_done(),
+ * tevent_req_error() or tevent_req_nomem() macro.
+ *
+ * This for debugging only.
+ */
+ const char *finish_location;
+
+ /**
+ * @brief The location where the request was canceled
+ *
+ * This uses the __location__ macro via the
+ * tevent_req_cancel() macro.
+ *
+ * This for debugging only.
+ */
+ const char *cancel_location;
+
+ /**
+ * @brief The external state - will be queried by the caller
+ *
+ * While the async request is being processed, state will remain in
+ * TEVENT_REQ_IN_PROGRESS. A request is finished if
+ * req->state>=TEVENT_REQ_DONE.
+ */
+ enum tevent_req_state state;
+
+ /**
+ * @brief status code when finished
+ *
+ * This status can be queried in the async completion function. It
+ * will be set to 0 when everything went fine.
+ */
+ uint64_t error;
+
+ /**
+ * @brief the immediate event used by tevent_req_post
+ *
+ */
+ struct tevent_immediate *trigger;
+
+ /**
+ * @brief the timer event if tevent_req_set_endtime was used
+ *
+ */
+ struct tevent_timer *timer;
+ } internal;
+};
+
+struct tevent_fd {
+ struct tevent_fd *prev, *next;
+ struct tevent_context *event_ctx;
+ int fd;
+ uint16_t flags; /* see TEVENT_FD_* flags */
+ tevent_fd_handler_t handler;
+ tevent_fd_close_fn_t close_fn;
+ /* this is private for the specific handler */
+ void *private_data;
+ /* this is for debugging only! */
+ const char *handler_name;
+ const char *location;
+ /* this is private for the events_ops implementation */
+ uint16_t additional_flags;
+ void *additional_data;
+};
+
+struct tevent_timer {
+ struct tevent_timer *prev, *next;
+ struct tevent_context *event_ctx;
+ struct timeval next_event;
+ tevent_timer_handler_t handler;
+ /* this is private for the specific handler */
+ void *private_data;
+ /* this is for debugging only! */
+ const char *handler_name;
+ const char *location;
+ /* this is private for the events_ops implementation */
+ void *additional_data;
+};
+
+struct tevent_immediate {
+ struct tevent_immediate *prev, *next;
+ struct tevent_context *event_ctx;
+ tevent_immediate_handler_t handler;
+ /* this is private for the specific handler */
+ void *private_data;
+ /* this is for debugging only! */
+ const char *handler_name;
+ const char *create_location;
+ const char *schedule_location;
+ /* this is private for the events_ops implementation */
+ void (*cancel_fn)(struct tevent_immediate *im);
+ void *additional_data;
+};
+
+struct tevent_signal {
+ struct tevent_signal *prev, *next;
+ struct tevent_context *event_ctx;
+ int signum;
+ int sa_flags;
+ tevent_signal_handler_t handler;
+ /* this is private for the specific handler */
+ void *private_data;
+ /* this is for debugging only! */
+ const char *handler_name;
+ const char *location;
+ /* this is private for the events_ops implementation */
+ void *additional_data;
+};
+
+struct tevent_debug_ops {
+ void (*debug)(void *context, enum tevent_debug_level level,
+ const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
+ void *context;
+};
+
+void tevent_debug(struct tevent_context *ev, enum tevent_debug_level level,
+ const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+
+struct tevent_context {
+ /* the specific events implementation */
+ const struct tevent_ops *ops;
+
+ /* list of fd events - used by common code */
+ struct tevent_fd *fd_events;
+
+ /* list of timed events - used by common code */
+ struct tevent_timer *timer_events;
+
+ /* list of immediate events - used by common code */
+ struct tevent_immediate *immediate_events;
+
+ /* list of signal events - used by common code */
+ struct tevent_signal *signal_events;
+
+ /* this is private for the events_ops implementation */
+ void *additional_data;
+
+ /* pipe hack used with signal handlers */
+ struct tevent_fd *pipe_fde;
+ int pipe_fds[2];
+
+ /* debugging operations */
+ struct tevent_debug_ops debug_ops;
+
+ /* info about the nesting status */
+ struct {
+ bool allowed;
+ uint32_t level;
+ tevent_nesting_hook hook_fn;
+ void *hook_private;
+ } nesting;
+};
+
+
+int tevent_common_context_destructor(struct tevent_context *ev);
+int tevent_common_loop_wait(struct tevent_context *ev,
+ const char *location);
+
+int tevent_common_fd_destructor(struct tevent_fd *fde);
+struct tevent_fd *tevent_common_add_fd(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int fd,
+ uint16_t flags,
+ tevent_fd_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+void tevent_common_fd_set_close_fn(struct tevent_fd *fde,
+ tevent_fd_close_fn_t close_fn);
+uint16_t tevent_common_fd_get_flags(struct tevent_fd *fde);
+void tevent_common_fd_set_flags(struct tevent_fd *fde, uint16_t flags);
+
+struct tevent_timer *tevent_common_add_timer(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ struct timeval next_event,
+ tevent_timer_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+struct timeval tevent_common_loop_timer_delay(struct tevent_context *);
+
+void tevent_common_schedule_immediate(struct tevent_immediate *im,
+ struct tevent_context *ev,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+bool tevent_common_loop_immediate(struct tevent_context *ev);
+
+struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int signum,
+ int sa_flags,
+ tevent_signal_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+int tevent_common_check_signal(struct tevent_context *ev);
+void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se);
+
+bool tevent_standard_init(void);
+bool tevent_select_init(void);
+#ifdef HAVE_EPOLL
+bool tevent_epoll_init(void);
+#endif
--- /dev/null
+# tevent_liboop.lo - a libtool object file
+# Generated by ltmain.sh - GNU libtool 1.5.26 Debian 1.5.26-1ubuntu1 (1.1220.2.493 2008/02/01 16:58:18)
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+ Infrastructure for async requests
+ Copyright (C) Volker Lendecke 2008
+ Copyright (C) Stefan Metzmacher 2009
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <atalk/tevent.h>
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+struct tevent_queue_entry {
+ struct tevent_queue_entry *prev, *next;
+ struct tevent_queue *queue;
+
+ bool triggered;
+
+ struct tevent_req *req;
+ struct tevent_context *ev;
+
+ tevent_queue_trigger_fn_t trigger;
+ void *private_data;
+};
+
+struct tevent_queue {
+ const char *name;
+ const char *location;
+
+ bool running;
+ struct tevent_immediate *immediate;
+
+ size_t length;
+ struct tevent_queue_entry *list;
+};
+
+static void tevent_queue_immediate_trigger(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_data);
+
+static int tevent_queue_entry_destructor(struct tevent_queue_entry *e)
+{
+ struct tevent_queue *q = e->queue;
+
+ if (!q) {
+ return 0;
+ }
+
+ DLIST_REMOVE(q->list, e);
+ q->length--;
+
+ if (!q->running) {
+ return 0;
+ }
+
+ if (!q->list) {
+ return 0;
+ }
+
+ if (q->list->triggered) {
+ return 0;
+ }
+
+ tevent_schedule_immediate(q->immediate,
+ q->list->ev,
+ tevent_queue_immediate_trigger,
+ q);
+
+ return 0;
+}
+
+static int tevent_queue_destructor(struct tevent_queue *q)
+{
+ q->running = false;
+
+ while (q->list) {
+ struct tevent_queue_entry *e = q->list;
+ talloc_free(e);
+ }
+
+ return 0;
+}
+
+struct tevent_queue *_tevent_queue_create(TALLOC_CTX *mem_ctx,
+ const char *name,
+ const char *location)
+{
+ struct tevent_queue *queue;
+
+ queue = talloc_zero(mem_ctx, struct tevent_queue);
+ if (!queue) {
+ return NULL;
+ }
+
+ queue->name = talloc_strdup(queue, name);
+ if (!queue->name) {
+ talloc_free(queue);
+ return NULL;
+ }
+ queue->immediate = tevent_create_immediate(queue);
+ if (!queue->immediate) {
+ talloc_free(queue);
+ return NULL;
+ }
+
+ queue->location = location;
+
+ /* queue is running by default */
+ queue->running = true;
+
+ talloc_set_destructor(queue, tevent_queue_destructor);
+ return queue;
+}
+
+static void tevent_queue_immediate_trigger(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct tevent_queue *q = talloc_get_type(private_data,
+ struct tevent_queue);
+
+ if (!q->running) {
+ return;
+ }
+
+ q->list->triggered = true;
+ q->list->trigger(q->list->req, q->list->private_data);
+}
+
+bool tevent_queue_add(struct tevent_queue *queue,
+ struct tevent_context *ev,
+ struct tevent_req *req,
+ tevent_queue_trigger_fn_t trigger,
+ void *private_data)
+{
+ struct tevent_queue_entry *e;
+
+ e = talloc_zero(req, struct tevent_queue_entry);
+ if (e == NULL) {
+ return false;
+ }
+
+ e->queue = queue;
+ e->req = req;
+ e->ev = ev;
+ e->trigger = trigger;
+ e->private_data = private_data;
+
+ DLIST_ADD_END(queue->list, e, struct tevent_queue_entry *);
+ queue->length++;
+ talloc_set_destructor(e, tevent_queue_entry_destructor);
+
+ if (!queue->running) {
+ return true;
+ }
+
+ if (queue->list->triggered) {
+ return true;
+ }
+
+ tevent_schedule_immediate(queue->immediate,
+ queue->list->ev,
+ tevent_queue_immediate_trigger,
+ queue);
+
+ return true;
+}
+
+void tevent_queue_start(struct tevent_queue *queue)
+{
+ if (queue->running) {
+ /* already started */
+ return;
+ }
+
+ queue->running = true;
+
+ if (!queue->list) {
+ return;
+ }
+
+ if (queue->list->triggered) {
+ return;
+ }
+
+ tevent_schedule_immediate(queue->immediate,
+ queue->list->ev,
+ tevent_queue_immediate_trigger,
+ queue);
+}
+
+void tevent_queue_stop(struct tevent_queue *queue)
+{
+ queue->running = false;
+}
+
+size_t tevent_queue_length(struct tevent_queue *queue)
+{
+ return queue->length;
+}
--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+ Infrastructure for async requests
+ Copyright (C) Volker Lendecke 2008
+ Copyright (C) Stefan Metzmacher 2009
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <atalk/tevent.h>
+
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+/**
+ * @brief The default print function for creating debug messages
+ * @param[in] req The request to be printed
+ * @param[in] mem_ctx The memory context for the result
+ * @retval Text representation of req
+ *
+ * The function should not be used by users of the asynx API,
+ * but custom print function can use it and append custom text
+ * to the string.
+ */
+
+char *tevent_req_default_print(struct tevent_req *req, TALLOC_CTX *mem_ctx)
+{
+ return talloc_asprintf(mem_ctx,
+ "tevent_req[%p/%s]: state[%d] error[%lld (0x%llX)] "
+ " state[%s (%p)] timer[%p]",
+ req, req->internal.create_location,
+ req->internal.state,
+ (unsigned long long)req->internal.error,
+ (unsigned long long)req->internal.error,
+ talloc_get_name(req->data),
+ req->data,
+ req->internal.timer
+ );
+}
+
+/**
+ * @brief Print an tevent_req structure in debug messages
+ * @param[in] mem_ctx The memory context for the result
+ * @param[in] req The request to be printed
+ * @retval Text representation of req
+ *
+ * This function should be used by callers of the async API
+ */
+
+char *tevent_req_print(TALLOC_CTX *mem_ctx, struct tevent_req *req)
+{
+ if (!req->private_print) {
+ return tevent_req_default_print(req, mem_ctx);
+ }
+
+ return req->private_print(req, mem_ctx);
+}
+
+/**
+ * @brief Create an async request
+ * @param[in] mem_ctx The memory context for the result
+ * @param[in] ev The event context this async request will be driven by
+ * @retval A new async request
+ *
+ * The new async request will be initialized in state ASYNC_REQ_IN_PROGRESS
+ */
+
+struct tevent_req *_tevent_req_create(TALLOC_CTX *mem_ctx,
+ void *pdata,
+ size_t data_size,
+ const char *type,
+ const char *location)
+{
+ struct tevent_req *req;
+ void **ppdata = (void **)pdata;
+ void *data;
+
+ req = talloc_zero(mem_ctx, struct tevent_req);
+ if (req == NULL) {
+ return NULL;
+ }
+ req->internal.private_type = type;
+ req->internal.create_location = location;
+ req->internal.finish_location = NULL;
+ req->internal.state = TEVENT_REQ_IN_PROGRESS;
+ req->internal.trigger = tevent_create_immediate(req);
+ if (!req->internal.trigger) {
+ talloc_free(req);
+ return NULL;
+ }
+
+ data = talloc_zero_size(req, data_size);
+ if (data == NULL) {
+ talloc_free(req);
+ return NULL;
+ }
+ talloc_set_name_const(data, type);
+
+ req->data = data;
+
+ *ppdata = data;
+ return req;
+}
+
+void _tevent_req_notify_callback(struct tevent_req *req, const char *location)
+{
+ req->internal.finish_location = location;
+ if (req->async.fn != NULL) {
+ req->async.fn(req);
+ }
+}
+
+static void tevent_req_finish(struct tevent_req *req,
+ enum tevent_req_state state,
+ const char *location)
+{
+ req->internal.state = state;
+ _tevent_req_notify_callback(req, location);
+}
+
+/**
+ * @brief An async request has successfully finished
+ * @param[in] req The finished request
+ *
+ * tevent_req_done is to be used by implementors of async requests. When a
+ * request is successfully finished, this function calls the user's completion
+ * function.
+ */
+
+void _tevent_req_done(struct tevent_req *req,
+ const char *location)
+{
+ tevent_req_finish(req, TEVENT_REQ_DONE, location);
+}
+
+/**
+ * @brief An async request has seen an error
+ * @param[in] req The request with an error
+ * @param[in] error The error code
+ *
+ * tevent_req_done is to be used by implementors of async requests. When a
+ * request can not successfully completed, the implementation should call this
+ * function with the appropriate status code.
+ *
+ * If error is 0 the function returns false and does nothing more.
+ *
+ * Call pattern would be
+ * \code
+ * int error = first_function();
+ * if (tevent_req_error(req, error)) {
+ * return;
+ * }
+ *
+ * error = second_function();
+ * if (tevent_req_error(req, error)) {
+ * return;
+ * }
+ *
+ * tevent_req_done(req);
+ * return;
+ * \endcode
+ */
+
+bool _tevent_req_error(struct tevent_req *req,
+ uint64_t error,
+ const char *location)
+{
+ if (error == 0) {
+ return false;
+ }
+
+ req->internal.error = error;
+ tevent_req_finish(req, TEVENT_REQ_USER_ERROR, location);
+ return true;
+}
+
+/**
+ * @brief Helper function for nomem check
+ * @param[in] p The pointer to be checked
+ * @param[in] req The request being processed
+ *
+ * Convenience helper to easily check alloc failure within a callback
+ * implementing the next step of an async request.
+ *
+ * Call pattern would be
+ * \code
+ * p = talloc(mem_ctx, bla);
+ * if (tevent_req_nomem(p, req)) {
+ * return;
+ * }
+ * \endcode
+ */
+
+bool _tevent_req_nomem(const void *p,
+ struct tevent_req *req,
+ const char *location)
+{
+ if (p != NULL) {
+ return false;
+ }
+ tevent_req_finish(req, TEVENT_REQ_NO_MEMORY, location);
+ return true;
+}
+
+/**
+ * @brief Immediate event callback
+ * @param[in] ev Event context
+ * @param[in] im The immediate event
+ * @param[in] priv The async request to be finished
+ */
+static void tevent_req_trigger(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct tevent_req *req = talloc_get_type(private_data,
+ struct tevent_req);
+
+ tevent_req_finish(req, req->internal.state,
+ req->internal.finish_location);
+}
+
+/**
+ * @brief Finish a request before the caller had the change to set the callback
+ * @param[in] req The finished request
+ * @param[in] ev The tevent_context for the timed event
+ * @retval req will be returned
+ *
+ * An implementation of an async request might find that it can either finish
+ * the request without waiting for an external event, or it can't even start
+ * the engine. To present the illusion of a callback to the user of the API,
+ * the implementation can call this helper function which triggers an
+ * immediate timed event. This way the caller can use the same calling
+ * conventions, independent of whether the request was actually deferred.
+ */
+
+struct tevent_req *tevent_req_post(struct tevent_req *req,
+ struct tevent_context *ev)
+{
+ tevent_schedule_immediate(req->internal.trigger,
+ ev, tevent_req_trigger, req);
+ return req;
+}
+
+/**
+ * @brief This function destroys the attached private data
+ * @param[in] req The request to poll
+ * @retval The boolean form of "is in progress".
+ *
+ * This function can be used to ask if the given request
+ * is still in progress.
+ *
+ * This function is typically used by sync wrapper functions.
+ */
+bool tevent_req_is_in_progress(struct tevent_req *req)
+{
+ if (req->internal.state == TEVENT_REQ_IN_PROGRESS) {
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * @brief This function destroys the attached private data
+ * @param[in] req The finished request
+ *
+ * This function can be called as last action of a _recv()
+ * function, it destroys the data attached to the tevent_req.
+ */
+void tevent_req_received(struct tevent_req *req)
+{
+ TALLOC_FREE(req->data);
+ req->private_print = NULL;
+
+ TALLOC_FREE(req->internal.trigger);
+ TALLOC_FREE(req->internal.timer);
+
+ req->internal.state = TEVENT_REQ_RECEIVED;
+}
+
+/**
+ * @brief This function destroys the attached private data
+ * @param[in] req The request to poll
+ * @param[in] ev The tevent_context to be used
+ * @retval If a critical error has happened in the
+ * tevent loop layer false is returned.
+ * Otherwise true is returned.
+ * This is not the return value of the given request!
+ *
+ * This function can be used to actively poll for the
+ * given request to finish.
+ *
+ * Note: this should only be used if the given tevent context
+ * was created by the caller, to avoid event loop nesting.
+ *
+ * This function is typically used by sync wrapper functions.
+ */
+bool tevent_req_poll(struct tevent_req *req,
+ struct tevent_context *ev)
+{
+ while (tevent_req_is_in_progress(req)) {
+ int ret;
+
+ ret = tevent_loop_once(ev);
+ if (ret != 0) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool tevent_req_is_error(struct tevent_req *req, enum tevent_req_state *state,
+ uint64_t *error)
+{
+ if (req->internal.state == TEVENT_REQ_DONE) {
+ return false;
+ }
+ if (req->internal.state == TEVENT_REQ_USER_ERROR) {
+ *error = req->internal.error;
+ }
+ *state = req->internal.state;
+ return true;
+}
+
+static void tevent_req_timedout(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval now,
+ void *private_data)
+{
+ struct tevent_req *req = talloc_get_type(private_data,
+ struct tevent_req);
+
+ TALLOC_FREE(req->internal.timer);
+
+ tevent_req_finish(req, TEVENT_REQ_TIMED_OUT, __FUNCTION__);
+}
+
+bool tevent_req_set_endtime(struct tevent_req *req,
+ struct tevent_context *ev,
+ struct timeval endtime)
+{
+ TALLOC_FREE(req->internal.timer);
+
+ req->internal.timer = tevent_add_timer(ev, req, endtime,
+ tevent_req_timedout,
+ req);
+ if (tevent_req_nomem(req->internal.timer, req)) {
+ return false;
+ }
+
+ return true;
+}
+
+void tevent_req_set_callback(struct tevent_req *req, tevent_req_fn fn, void *pvt)
+{
+ req->async.fn = fn;
+ req->async.private_data = pvt;
+}
+
+void *_tevent_req_callback_data(struct tevent_req *req)
+{
+ return req->async.private_data;
+}
+
+void *_tevent_req_data(struct tevent_req *req)
+{
+ return req->data;
+}
+
+/**
+ * @brief This function sets a print function for the given request
+ * @param[in] req The given request
+ * @param[in] fn A pointer to the print function
+ *
+ * This function can be used to setup a print function for the given request.
+ * This will be triggered if the tevent_req_print() function was
+ * called on the given request.
+ *
+ * Note: this function should only be used for debugging.
+ */
+void tevent_req_set_print_fn(struct tevent_req *req, tevent_req_print_fn fn)
+{
+ req->private_print = fn;
+}
+
+/**
+ * @brief This function sets a cancel function for the given request
+ * @param[in] req The given request
+ * @param[in] fn A pointer to the cancel function
+ *
+ * This function can be used to setup a cancel function for the given request.
+ * This will be triggered if the tevent_req_cancel() function was
+ * called on the given request.
+ *
+ */
+void tevent_req_set_cancel_fn(struct tevent_req *req, tevent_req_cancel_fn fn)
+{
+ req->private_cancel = fn;
+}
+
+/**
+ * @brief This function tries to cancel the given request
+ * @param[in] req The given request
+ * @param[in] location Automaticly filled with the __location__ macro
+ * via the tevent_req_cancel() macro. This is for debugging
+ * only!
+ * @retval This function returns true is the request is cancelable.
+ * Otherwise false is returned.
+ *
+ * This function can be used to cancel the given request.
+ *
+ * It is only possible to cancel a request when the implementation
+ * has registered a cancel function via the tevent_req_set_cancel_fn().
+ *
+ * Note: Even if the function returns true, the caller need to wait
+ * for the function to complete normally.
+ * Only the _recv() function of the given request indicates
+ * if the request was really canceled.
+ */
+bool _tevent_req_cancel(struct tevent_req *req, const char *location)
+{
+ if (req->private_cancel == NULL) {
+ return false;
+ }
+
+ return req->private_cancel(req);
+}
--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+ main select loop and event handling
+ Copyright (C) Andrew Tridgell 2003-2005
+ Copyright (C) Stefan Metzmacher 2005-2009
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <atalk/tevent.h>
+
+#include "tevent_util.h"
+#include "tevent_internal.h"
+
+struct select_event_context {
+ /* a pointer back to the generic event_context */
+ struct tevent_context *ev;
+
+ /* the maximum file descriptor number in fd_events */
+ int maxfd;
+
+ /* information for exiting from the event loop */
+ int exit_code;
+};
+
+/*
+ create a select_event_context structure.
+*/
+static int select_event_context_init(struct tevent_context *ev)
+{
+ struct select_event_context *select_ev;
+
+ select_ev = talloc_zero(ev, struct select_event_context);
+ if (!select_ev) return -1;
+ select_ev->ev = ev;
+
+ ev->additional_data = select_ev;
+ return 0;
+}
+
+/*
+ recalculate the maxfd
+*/
+static void calc_maxfd(struct select_event_context *select_ev)
+{
+ struct tevent_fd *fde;
+
+ select_ev->maxfd = 0;
+ for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
+ if (fde->fd > select_ev->maxfd) {
+ select_ev->maxfd = fde->fd;
+ }
+ }
+}
+
+
+/* to mark the ev->maxfd invalid
+ * this means we need to recalculate it
+ */
+#define EVENT_INVALID_MAXFD (-1)
+
+/*
+ destroy an fd_event
+*/
+static int select_event_fd_destructor(struct tevent_fd *fde)
+{
+ struct tevent_context *ev = fde->event_ctx;
+ struct select_event_context *select_ev = NULL;
+
+ if (ev) {
+ select_ev = talloc_get_type(ev->additional_data,
+ struct select_event_context);
+
+ if (select_ev->maxfd == fde->fd) {
+ select_ev->maxfd = EVENT_INVALID_MAXFD;
+ }
+ }
+
+ return tevent_common_fd_destructor(fde);
+}
+
+/*
+ add a fd based event
+ return NULL on failure (memory allocation error)
+*/
+static struct tevent_fd *select_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
+ int fd, uint16_t flags,
+ tevent_fd_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
+ struct select_event_context);
+ struct tevent_fd *fde;
+
+ fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
+ handler, private_data,
+ handler_name, location);
+ if (!fde) return NULL;
+
+ if (fde->fd > select_ev->maxfd) {
+ select_ev->maxfd = fde->fd;
+ }
+ talloc_set_destructor(fde, select_event_fd_destructor);
+
+ return fde;
+}
+
+/*
+ event loop handling using select()
+*/
+static int select_event_loop_select(struct select_event_context *select_ev, struct timeval *tvalp)
+{
+ fd_set r_fds, w_fds;
+ struct tevent_fd *fde;
+ int selrtn;
+
+ /* we maybe need to recalculate the maxfd */
+ if (select_ev->maxfd == EVENT_INVALID_MAXFD) {
+ calc_maxfd(select_ev);
+ }
+
+ FD_ZERO(&r_fds);
+ FD_ZERO(&w_fds);
+
+ /* setup any fd events */
+ for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
+ if (fde->flags & TEVENT_FD_READ) {
+ FD_SET(fde->fd, &r_fds);
+ }
+ if (fde->flags & TEVENT_FD_WRITE) {
+ FD_SET(fde->fd, &w_fds);
+ }
+ }
+
+ if (select_ev->ev->signal_events &&
+ tevent_common_check_signal(select_ev->ev)) {
+ return 0;
+ }
+
+ selrtn = select(select_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
+
+ if (selrtn == -1 && errno == EINTR &&
+ select_ev->ev->signal_events) {
+ tevent_common_check_signal(select_ev->ev);
+ return 0;
+ }
+
+ if (selrtn == -1 && errno == EBADF) {
+ /* the socket is dead! this should never
+ happen as the socket should have first been
+ made readable and that should have removed
+ the event, so this must be a bug. This is a
+ fatal error. */
+ tevent_debug(select_ev->ev, TEVENT_DEBUG_FATAL,
+ "ERROR: EBADF on select_event_loop_once\n");
+ select_ev->exit_code = EBADF;
+ return -1;
+ }
+
+ if (selrtn == 0 && tvalp) {
+ /* we don't care about a possible delay here */
+ tevent_common_loop_timer_delay(select_ev->ev);
+ return 0;
+ }
+
+ if (selrtn > 0) {
+ /* at least one file descriptor is ready - check
+ which ones and call the handler, being careful to allow
+ the handler to remove itself when called */
+ for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
+ uint16_t flags = 0;
+
+ if (FD_ISSET(fde->fd, &r_fds)) flags |= TEVENT_FD_READ;
+ if (FD_ISSET(fde->fd, &w_fds)) flags |= TEVENT_FD_WRITE;
+ if (flags) {
+ fde->handler(select_ev->ev, fde, flags, fde->private_data);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ do a single event loop using the events defined in ev
+*/
+static int select_event_loop_once(struct tevent_context *ev, const char *location)
+{
+ struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
+ struct select_event_context);
+ struct timeval tval;
+
+ if (ev->signal_events &&
+ tevent_common_check_signal(ev)) {
+ return 0;
+ }
+
+ if (ev->immediate_events &&
+ tevent_common_loop_immediate(ev)) {
+ return 0;
+ }
+
+ tval = tevent_common_loop_timer_delay(ev);
+ if (tevent_timeval_is_zero(&tval)) {
+ return 0;
+ }
+
+ return select_event_loop_select(select_ev, &tval);
+}
+
+static const struct tevent_ops select_event_ops = {
+ .context_init = select_event_context_init,
+ .add_fd = select_event_add_fd,
+ .set_fd_close_fn = tevent_common_fd_set_close_fn,
+ .get_fd_flags = tevent_common_fd_get_flags,
+ .set_fd_flags = tevent_common_fd_set_flags,
+ .add_timer = tevent_common_add_timer,
+ .schedule_immediate = tevent_common_schedule_immediate,
+ .add_signal = tevent_common_add_signal,
+ .loop_once = select_event_loop_once,
+ .loop_wait = tevent_common_loop_wait,
+};
+
+bool tevent_select_init(void)
+{
+ return tevent_register_backend("select", &select_event_ops);
+}
--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+
+ common events code for signal events
+
+ Copyright (C) Andrew Tridgell 2007
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <atalk/tevent.h>
+
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+#define TEVENT_NUM_SIGNALS 64
+
+/* maximum number of SA_SIGINFO signals to hold in the queue.
+ NB. This *MUST* be a power of 2, in order for the ring buffer
+ wrap to work correctly. Thanks to Petr Vandrovec <petr@vandrovec.name>
+ for this. */
+
+#define TEVENT_SA_INFO_QUEUE_COUNT 64
+
+struct tevent_sigcounter {
+ uint32_t count;
+ uint32_t seen;
+};
+
+#define TEVENT_SIG_INCREMENT(s) (s).count++
+#define TEVENT_SIG_SEEN(s, n) (s).seen += (n)
+#define TEVENT_SIG_PENDING(s) ((s).seen != (s).count)
+
+struct tevent_common_signal_list {
+ struct tevent_common_signal_list *prev, *next;
+ struct tevent_signal *se;
+};
+
+/*
+ the poor design of signals means that this table must be static global
+*/
+static struct tevent_sig_state {
+ struct tevent_common_signal_list *sig_handlers[TEVENT_NUM_SIGNALS+1];
+ struct sigaction *oldact[TEVENT_NUM_SIGNALS+1];
+ struct tevent_sigcounter signal_count[TEVENT_NUM_SIGNALS+1];
+ struct tevent_sigcounter got_signal;
+#ifdef SA_SIGINFO
+ /* with SA_SIGINFO we get quite a lot of info per signal */
+ siginfo_t *sig_info[TEVENT_NUM_SIGNALS+1];
+ struct tevent_sigcounter sig_blocked[TEVENT_NUM_SIGNALS+1];
+#endif
+} *sig_state;
+
+/*
+ return number of sigcounter events not processed yet
+*/
+static uint32_t tevent_sig_count(struct tevent_sigcounter s)
+{
+ return s.count - s.seen;
+}
+
+/*
+ signal handler - redirects to registered signals
+*/
+static void tevent_common_signal_handler(int signum)
+{
+ char c = 0;
+ ssize_t res;
+ struct tevent_common_signal_list *sl;
+ struct tevent_context *ev = NULL;
+ int saved_errno = errno;
+
+ TEVENT_SIG_INCREMENT(sig_state->signal_count[signum]);
+ TEVENT_SIG_INCREMENT(sig_state->got_signal);
+
+ /* Write to each unique event context. */
+ for (sl = sig_state->sig_handlers[signum]; sl; sl = sl->next) {
+ if (sl->se->event_ctx && sl->se->event_ctx != ev) {
+ ev = sl->se->event_ctx;
+ /* doesn't matter if this pipe overflows */
+ res = write(ev->pipe_fds[1], &c, 1);
+ }
+ }
+
+ errno = saved_errno;
+}
+
+#ifdef SA_SIGINFO
+/*
+ signal handler with SA_SIGINFO - redirects to registered signals
+*/
+static void tevent_common_signal_handler_info(int signum, siginfo_t *info,
+ void *uctx)
+{
+ uint32_t count = tevent_sig_count(sig_state->signal_count[signum]);
+ /* sig_state->signal_count[signum].seen % TEVENT_SA_INFO_QUEUE_COUNT
+ * is the base of the unprocessed signals in the ringbuffer. */
+ uint32_t ofs = (sig_state->signal_count[signum].seen + count) %
+ TEVENT_SA_INFO_QUEUE_COUNT;
+ sig_state->sig_info[signum][ofs] = *info;
+
+ tevent_common_signal_handler(signum);
+
+ /* handle SA_SIGINFO */
+ if (count+1 == TEVENT_SA_INFO_QUEUE_COUNT) {
+ /* we've filled the info array - block this signal until
+ these ones are delivered */
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, signum);
+ sigprocmask(SIG_BLOCK, &set, NULL);
+ TEVENT_SIG_INCREMENT(sig_state->sig_blocked[signum]);
+ }
+}
+#endif
+
+static int tevent_common_signal_list_destructor(struct tevent_common_signal_list *sl)
+{
+ if (sig_state->sig_handlers[sl->se->signum]) {
+ DLIST_REMOVE(sig_state->sig_handlers[sl->se->signum], sl);
+ }
+ return 0;
+}
+
+/*
+ destroy a signal event
+*/
+static int tevent_signal_destructor(struct tevent_signal *se)
+{
+ struct tevent_common_signal_list *sl;
+ sl = talloc_get_type(se->additional_data,
+ struct tevent_common_signal_list);
+
+ if (se->event_ctx) {
+ DLIST_REMOVE(se->event_ctx->signal_events, se);
+ }
+
+ talloc_free(sl);
+
+ if (sig_state->sig_handlers[se->signum] == NULL) {
+ /* restore old handler, if any */
+ if (sig_state->oldact[se->signum]) {
+ sigaction(se->signum, sig_state->oldact[se->signum], NULL);
+ sig_state->oldact[se->signum] = NULL;
+ }
+#ifdef SA_SIGINFO
+ if (se->sa_flags & SA_SIGINFO) {
+ if (sig_state->sig_info[se->signum]) {
+ talloc_free(sig_state->sig_info[se->signum]);
+ sig_state->sig_info[se->signum] = NULL;
+ }
+ }
+#endif
+ }
+
+ return 0;
+}
+
+/*
+ this is part of the pipe hack needed to avoid the signal race condition
+*/
+static void signal_pipe_handler(struct tevent_context *ev, struct tevent_fd *fde,
+ uint16_t flags, void *_private)
+{
+ char c[16];
+ ssize_t res;
+ /* its non-blocking, doesn't matter if we read too much */
+ res = read(fde->fd, c, sizeof(c));
+}
+
+/*
+ add a signal event
+ return NULL on failure (memory allocation error)
+*/
+struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int signum,
+ int sa_flags,
+ tevent_signal_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ struct tevent_signal *se;
+ struct tevent_common_signal_list *sl;
+ sigset_t set, oldset;
+
+ if (signum >= TEVENT_NUM_SIGNALS) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /* the sig_state needs to be on a global context as it can last across
+ multiple event contexts */
+ if (sig_state == NULL) {
+ sig_state = talloc_zero(talloc_autofree_context(), struct tevent_sig_state);
+ if (sig_state == NULL) {
+ return NULL;
+ }
+ }
+
+ se = talloc(mem_ctx?mem_ctx:ev, struct tevent_signal);
+ if (se == NULL) return NULL;
+
+ se->event_ctx = ev;
+ se->signum = signum;
+ se->sa_flags = sa_flags;
+ se->handler = handler;
+ se->private_data = private_data;
+ se->handler_name = handler_name;
+ se->location = location;
+ se->additional_data = NULL;
+
+ sl = talloc(se, struct tevent_common_signal_list);
+ if (!sl) {
+ talloc_free(se);
+ return NULL;
+ }
+ sl->se = se;
+ se->additional_data = sl;
+
+ /* Ensure, no matter the destruction order, that we always have a handle on the global sig_state */
+ if (!talloc_reference(se, sig_state)) {
+ talloc_free(se);
+ return NULL;
+ }
+
+ /* we need to setup the pipe hack handler if not already
+ setup */
+ if (ev->pipe_fde == NULL) {
+ if (pipe(ev->pipe_fds) == -1) {
+ talloc_free(se);
+ return NULL;
+ }
+ ev_set_blocking(ev->pipe_fds[0], false);
+ ev_set_blocking(ev->pipe_fds[1], false);
+ ev->pipe_fde = tevent_add_fd(ev, ev, ev->pipe_fds[0],
+ TEVENT_FD_READ,
+ signal_pipe_handler, NULL);
+ if (!ev->pipe_fde) {
+ close(ev->pipe_fds[0]);
+ close(ev->pipe_fds[1]);
+ talloc_free(se);
+ return NULL;
+ }
+ }
+
+ /* only install a signal handler if not already installed */
+ if (sig_state->sig_handlers[signum] == NULL) {
+ struct sigaction act;
+ ZERO_STRUCT(act);
+ act.sa_handler = tevent_common_signal_handler;
+ act.sa_flags = sa_flags;
+#ifdef SA_SIGINFO
+ if (sa_flags & SA_SIGINFO) {
+ act.sa_handler = NULL;
+ act.sa_sigaction = tevent_common_signal_handler_info;
+ if (sig_state->sig_info[signum] == NULL) {
+ sig_state->sig_info[signum] =
+ talloc_zero_array(sig_state, siginfo_t,
+ TEVENT_SA_INFO_QUEUE_COUNT);
+ if (sig_state->sig_info[signum] == NULL) {
+ talloc_free(se);
+ return NULL;
+ }
+ }
+ }
+#endif
+ sig_state->oldact[signum] = talloc(sig_state, struct sigaction);
+ if (sig_state->oldact[signum] == NULL) {
+ talloc_free(se);
+ return NULL;
+ }
+ if (sigaction(signum, &act, sig_state->oldact[signum]) == -1) {
+ talloc_free(se);
+ return NULL;
+ }
+ }
+
+ DLIST_ADD(se->event_ctx->signal_events, se);
+
+ /* Make sure the signal doesn't come in while we're mangling list. */
+ sigemptyset(&set);
+ sigaddset(&set, signum);
+ sigprocmask(SIG_BLOCK, &set, &oldset);
+ DLIST_ADD(sig_state->sig_handlers[signum], sl);
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+
+ talloc_set_destructor(se, tevent_signal_destructor);
+ talloc_set_destructor(sl, tevent_common_signal_list_destructor);
+
+ return se;
+}
+
+
+/*
+ check if a signal is pending
+ return != 0 if a signal was pending
+*/
+int tevent_common_check_signal(struct tevent_context *ev)
+{
+ int i;
+
+ if (!sig_state || !TEVENT_SIG_PENDING(sig_state->got_signal)) {
+ return 0;
+ }
+
+ for (i=0;i<TEVENT_NUM_SIGNALS+1;i++) {
+ struct tevent_common_signal_list *sl, *next;
+ struct tevent_sigcounter counter = sig_state->signal_count[i];
+ uint32_t count = tevent_sig_count(counter);
+#ifdef SA_SIGINFO
+ /* Ensure we null out any stored siginfo_t entries
+ * after processing for debugging purposes. */
+ bool clear_processed_siginfo = false;
+#endif
+
+ if (count == 0) {
+ continue;
+ }
+ for (sl=sig_state->sig_handlers[i];sl;sl=next) {
+ struct tevent_signal *se = sl->se;
+ next = sl->next;
+#ifdef SA_SIGINFO
+ if (se->sa_flags & SA_SIGINFO) {
+ uint32_t j;
+
+ clear_processed_siginfo = true;
+
+ for (j=0;j<count;j++) {
+ /* sig_state->signal_count[i].seen
+ * % TEVENT_SA_INFO_QUEUE_COUNT is
+ * the base position of the unprocessed
+ * signals in the ringbuffer. */
+ uint32_t ofs = (counter.seen + j)
+ % TEVENT_SA_INFO_QUEUE_COUNT;
+ se->handler(ev, se, i, 1,
+ (void*)&sig_state->sig_info[i][ofs],
+ se->private_data);
+ }
+ if (se->sa_flags & SA_RESETHAND) {
+ talloc_free(se);
+ }
+ continue;
+ }
+#endif
+ se->handler(ev, se, i, count, NULL, se->private_data);
+ if (se->sa_flags & SA_RESETHAND) {
+ talloc_free(se);
+ }
+ }
+
+#ifdef SA_SIGINFO
+ if (clear_processed_siginfo) {
+ uint32_t j;
+ for (j=0;j<count;j++) {
+ uint32_t ofs = (counter.seen + j)
+ % TEVENT_SA_INFO_QUEUE_COUNT;
+ memset((void*)&sig_state->sig_info[i][ofs],
+ '\0',
+ sizeof(siginfo_t));
+ }
+ }
+#endif
+
+ TEVENT_SIG_SEEN(sig_state->signal_count[i], count);
+ TEVENT_SIG_SEEN(sig_state->got_signal, count);
+
+#ifdef SA_SIGINFO
+ if (TEVENT_SIG_PENDING(sig_state->sig_blocked[i])) {
+ /* We'd filled the queue, unblock the
+ signal now the queue is empty again.
+ Note we MUST do this after the
+ TEVENT_SIG_SEEN(sig_state->signal_count[i], count)
+ call to prevent a new signal running
+ out of room in the sig_state->sig_info[i][]
+ ring buffer. */
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, i);
+ TEVENT_SIG_SEEN(sig_state->sig_blocked[i],
+ tevent_sig_count(sig_state->sig_blocked[i]));
+ sigprocmask(SIG_UNBLOCK, &set, NULL);
+ }
+#endif
+ }
+
+ return 1;
+}
+
+void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se)
+{
+ struct tevent_common_signal_list *sl;
+ sl = talloc_get_type(se->additional_data,
+ struct tevent_common_signal_list);
+
+ tevent_common_signal_list_destructor(sl);
+
+ if (sig_state->sig_handlers[se->signum] == NULL) {
+ if (sig_state->oldact[se->signum]) {
+ sigaction(se->signum, sig_state->oldact[se->signum], NULL);
+ sig_state->oldact[se->signum] = NULL;
+ }
+ }
+ return;
+}
--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+ main select loop and event handling
+ Copyright (C) Andrew Tridgell 2003-2005
+ Copyright (C) Stefan Metzmacher 2005-2009
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ This is SAMBA's default event loop code
+
+ - we try to use epoll if configure detected support for it
+ otherwise we use select()
+ - if epoll is broken on the system or the kernel doesn't support it
+ at runtime we fallback to select()
+*/
+
+#include <atalk/tevent.h>
+
+#include "tevent_util.h"
+#include "tevent_internal.h"
+
+struct std_event_context {
+ /* a pointer back to the generic event_context */
+ struct tevent_context *ev;
+
+ /* the maximum file descriptor number in fd_events */
+ int maxfd;
+
+ /* information for exiting from the event loop */
+ int exit_code;
+
+ /* when using epoll this is the handle from epoll_create */
+ int epoll_fd;
+
+ /* our pid at the time the epoll_fd was created */
+ pid_t pid;
+};
+
+/* use epoll if it is available */
+#if HAVE_EPOLL
+/*
+ called when a epoll call fails, and we should fallback
+ to using select
+*/
+static void epoll_fallback_to_select(struct std_event_context *std_ev, const char *reason)
+{
+ tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
+ "%s (%s) - falling back to select()\n",
+ reason, strerror(errno));
+ close(std_ev->epoll_fd);
+ std_ev->epoll_fd = -1;
+ talloc_set_destructor(std_ev, NULL);
+}
+
+/*
+ map from TEVENT_FD_* to EPOLLIN/EPOLLOUT
+*/
+static uint32_t epoll_map_flags(uint16_t flags)
+{
+ uint32_t ret = 0;
+ if (flags & TEVENT_FD_READ) ret |= (EPOLLIN | EPOLLERR | EPOLLHUP);
+ if (flags & TEVENT_FD_WRITE) ret |= (EPOLLOUT | EPOLLERR | EPOLLHUP);
+ return ret;
+}
+
+/*
+ free the epoll fd
+*/
+static int epoll_ctx_destructor(struct std_event_context *std_ev)
+{
+ if (std_ev->epoll_fd != -1) {
+ close(std_ev->epoll_fd);
+ }
+ std_ev->epoll_fd = -1;
+ return 0;
+}
+
+/*
+ init the epoll fd
+*/
+static void epoll_init_ctx(struct std_event_context *std_ev)
+{
+ std_ev->epoll_fd = epoll_create(64);
+ std_ev->pid = getpid();
+ talloc_set_destructor(std_ev, epoll_ctx_destructor);
+}
+
+static void epoll_add_event(struct std_event_context *std_ev, struct tevent_fd *fde);
+
+/*
+ reopen the epoll handle when our pid changes
+ see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an
+ demonstration of why this is needed
+ */
+static void epoll_check_reopen(struct std_event_context *std_ev)
+{
+ struct tevent_fd *fde;
+
+ if (std_ev->pid == getpid()) {
+ return;
+ }
+
+ close(std_ev->epoll_fd);
+ std_ev->epoll_fd = epoll_create(64);
+ if (std_ev->epoll_fd == -1) {
+ tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
+ "Failed to recreate epoll handle after fork\n");
+ return;
+ }
+ std_ev->pid = getpid();
+ for (fde=std_ev->ev->fd_events;fde;fde=fde->next) {
+ epoll_add_event(std_ev, fde);
+ }
+}
+
+#define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT (1<<0)
+#define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR (1<<1)
+#define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR (1<<2)
+
+/*
+ add the epoll event to the given fd_event
+*/
+static void epoll_add_event(struct std_event_context *std_ev, struct tevent_fd *fde)
+{
+ struct epoll_event event;
+ if (std_ev->epoll_fd == -1) return;
+
+ fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+
+ /* if we don't want events yet, don't add an epoll_event */
+ if (fde->flags == 0) return;
+
+ ZERO_STRUCT(event);
+ event.events = epoll_map_flags(fde->flags);
+ event.data.ptr = fde;
+ if (epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event) != 0) {
+ epoll_fallback_to_select(std_ev, "EPOLL_CTL_ADD failed");
+ }
+ fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+
+ /* only if we want to read we want to tell the event handler about errors */
+ if (fde->flags & TEVENT_FD_READ) {
+ fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+ }
+}
+
+/*
+ delete the epoll event for given fd_event
+*/
+static void epoll_del_event(struct std_event_context *std_ev, struct tevent_fd *fde)
+{
+ struct epoll_event event;
+ if (std_ev->epoll_fd == -1) return;
+
+ fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+
+ /* if there's no epoll_event, we don't need to delete it */
+ if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) return;
+
+ ZERO_STRUCT(event);
+ event.events = epoll_map_flags(fde->flags);
+ event.data.ptr = fde;
+ epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event);
+ fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+}
+
+/*
+ change the epoll event to the given fd_event
+*/
+static void epoll_mod_event(struct std_event_context *std_ev, struct tevent_fd *fde)
+{
+ struct epoll_event event;
+ if (std_ev->epoll_fd == -1) return;
+
+ fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+
+ ZERO_STRUCT(event);
+ event.events = epoll_map_flags(fde->flags);
+ event.data.ptr = fde;
+ if (epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) {
+ epoll_fallback_to_select(std_ev, "EPOLL_CTL_MOD failed");
+ }
+
+ /* only if we want to read we want to tell the event handler about errors */
+ if (fde->flags & TEVENT_FD_READ) {
+ fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+ }
+}
+
+static void epoll_change_event(struct std_event_context *std_ev, struct tevent_fd *fde)
+{
+ bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
+ bool want_read = (fde->flags & TEVENT_FD_READ);
+ bool want_write= (fde->flags & TEVENT_FD_WRITE);
+
+ if (std_ev->epoll_fd == -1) return;
+
+ fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+
+ /* there's already an event */
+ if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) {
+ if (want_read || (want_write && !got_error)) {
+ epoll_mod_event(std_ev, fde);
+ return;
+ }
+ /*
+ * if we want to match the select behavior, we need to remove the epoll_event
+ * when the caller isn't interested in events.
+ *
+ * this is because epoll reports EPOLLERR and EPOLLHUP, even without asking for them
+ */
+ epoll_del_event(std_ev, fde);
+ return;
+ }
+
+ /* there's no epoll_event attached to the fde */
+ if (want_read || (want_write && !got_error)) {
+ epoll_add_event(std_ev, fde);
+ return;
+ }
+}
+
+/*
+ event loop handling using epoll
+*/
+static int epoll_event_loop(struct std_event_context *std_ev, struct timeval *tvalp)
+{
+ int ret, i;
+#define MAXEVENTS 1
+ struct epoll_event events[MAXEVENTS];
+ int timeout = -1;
+
+ if (std_ev->epoll_fd == -1) return -1;
+
+ if (tvalp) {
+ /* it's better to trigger timed events a bit later than to early */
+ timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000);
+ }
+
+ if (std_ev->ev->signal_events &&
+ tevent_common_check_signal(std_ev->ev)) {
+ return 0;
+ }
+
+ ret = epoll_wait(std_ev->epoll_fd, events, MAXEVENTS, timeout);
+
+ if (ret == -1 && errno == EINTR && std_ev->ev->signal_events) {
+ if (tevent_common_check_signal(std_ev->ev)) {
+ return 0;
+ }
+ }
+
+ if (ret == -1 && errno != EINTR) {
+ epoll_fallback_to_select(std_ev, "epoll_wait() failed");
+ return -1;
+ }
+
+ if (ret == 0 && tvalp) {
+ /* we don't care about a possible delay here */
+ tevent_common_loop_timer_delay(std_ev->ev);
+ return 0;
+ }
+
+ for (i=0;i<ret;i++) {
+ struct tevent_fd *fde = talloc_get_type(events[i].data.ptr,
+ struct tevent_fd);
+ uint16_t flags = 0;
+
+ if (fde == NULL) {
+ epoll_fallback_to_select(std_ev, "epoll_wait() gave bad data");
+ return -1;
+ }
+ if (events[i].events & (EPOLLHUP|EPOLLERR)) {
+ fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
+ /*
+ * if we only wait for TEVENT_FD_WRITE, we should not tell the
+ * event handler about it, and remove the epoll_event,
+ * as we only report errors when waiting for read events,
+ * to match the select() behavior
+ */
+ if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) {
+ epoll_del_event(std_ev, fde);
+ continue;
+ }
+ flags |= TEVENT_FD_READ;
+ }
+ if (events[i].events & EPOLLIN) flags |= TEVENT_FD_READ;
+ if (events[i].events & EPOLLOUT) flags |= TEVENT_FD_WRITE;
+ if (flags) {
+ fde->handler(std_ev->ev, fde, flags, fde->private_data);
+ break;
+ }
+ }
+
+ return 0;
+}
+#else
+#define epoll_init_ctx(std_ev)
+#define epoll_add_event(std_ev,fde)
+#define epoll_del_event(std_ev,fde)
+#define epoll_change_event(std_ev,fde)
+#define epoll_event_loop(std_ev,tvalp) (-1)
+#define epoll_check_reopen(std_ev)
+#endif
+
+/*
+ create a std_event_context structure.
+*/
+static int std_event_context_init(struct tevent_context *ev)
+{
+ struct std_event_context *std_ev;
+
+ std_ev = talloc_zero(ev, struct std_event_context);
+ if (!std_ev) return -1;
+ std_ev->ev = ev;
+ std_ev->epoll_fd = -1;
+
+ epoll_init_ctx(std_ev);
+
+ ev->additional_data = std_ev;
+ return 0;
+}
+
+/*
+ recalculate the maxfd
+*/
+static void calc_maxfd(struct std_event_context *std_ev)
+{
+ struct tevent_fd *fde;
+
+ std_ev->maxfd = 0;
+ for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
+ if (fde->fd > std_ev->maxfd) {
+ std_ev->maxfd = fde->fd;
+ }
+ }
+}
+
+
+/* to mark the ev->maxfd invalid
+ * this means we need to recalculate it
+ */
+#define EVENT_INVALID_MAXFD (-1)
+
+/*
+ destroy an fd_event
+*/
+static int std_event_fd_destructor(struct tevent_fd *fde)
+{
+ struct tevent_context *ev = fde->event_ctx;
+ struct std_event_context *std_ev = NULL;
+
+ if (ev) {
+ std_ev = talloc_get_type(ev->additional_data,
+ struct std_event_context);
+
+ epoll_check_reopen(std_ev);
+
+ if (std_ev->maxfd == fde->fd) {
+ std_ev->maxfd = EVENT_INVALID_MAXFD;
+ }
+
+ epoll_del_event(std_ev, fde);
+ }
+
+ return tevent_common_fd_destructor(fde);
+}
+
+/*
+ add a fd based event
+ return NULL on failure (memory allocation error)
+*/
+static struct tevent_fd *std_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
+ int fd, uint16_t flags,
+ tevent_fd_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
+ struct std_event_context);
+ struct tevent_fd *fde;
+
+ epoll_check_reopen(std_ev);
+
+ fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
+ handler, private_data,
+ handler_name, location);
+ if (!fde) return NULL;
+
+ if ((std_ev->maxfd != EVENT_INVALID_MAXFD)
+ && (fde->fd > std_ev->maxfd)) {
+ std_ev->maxfd = fde->fd;
+ }
+ talloc_set_destructor(fde, std_event_fd_destructor);
+
+ epoll_add_event(std_ev, fde);
+
+ return fde;
+}
+
+/*
+ set the fd event flags
+*/
+static void std_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
+{
+ struct tevent_context *ev;
+ struct std_event_context *std_ev;
+
+ if (fde->flags == flags) return;
+
+ ev = fde->event_ctx;
+ std_ev = talloc_get_type(ev->additional_data, struct std_event_context);
+
+ fde->flags = flags;
+
+ epoll_check_reopen(std_ev);
+
+ epoll_change_event(std_ev, fde);
+}
+
+/*
+ event loop handling using select()
+*/
+static int std_event_loop_select(struct std_event_context *std_ev, struct timeval *tvalp)
+{
+ fd_set r_fds, w_fds;
+ struct tevent_fd *fde;
+ int selrtn;
+
+ /* we maybe need to recalculate the maxfd */
+ if (std_ev->maxfd == EVENT_INVALID_MAXFD) {
+ calc_maxfd(std_ev);
+ }
+
+ FD_ZERO(&r_fds);
+ FD_ZERO(&w_fds);
+
+ /* setup any fd events */
+ for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
+ if (fde->flags & TEVENT_FD_READ) {
+ FD_SET(fde->fd, &r_fds);
+ }
+ if (fde->flags & TEVENT_FD_WRITE) {
+ FD_SET(fde->fd, &w_fds);
+ }
+ }
+
+ if (std_ev->ev->signal_events &&
+ tevent_common_check_signal(std_ev->ev)) {
+ return 0;
+ }
+
+ selrtn = select(std_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
+
+ if (selrtn == -1 && errno == EINTR &&
+ std_ev->ev->signal_events) {
+ tevent_common_check_signal(std_ev->ev);
+ return 0;
+ }
+
+ if (selrtn == -1 && errno == EBADF) {
+ /* the socket is dead! this should never
+ happen as the socket should have first been
+ made readable and that should have removed
+ the event, so this must be a bug. This is a
+ fatal error. */
+ tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
+ "ERROR: EBADF on std_event_loop_once\n");
+ std_ev->exit_code = EBADF;
+ return -1;
+ }
+
+ if (selrtn == 0 && tvalp) {
+ /* we don't care about a possible delay here */
+ tevent_common_loop_timer_delay(std_ev->ev);
+ return 0;
+ }
+
+ if (selrtn > 0) {
+ /* at least one file descriptor is ready - check
+ which ones and call the handler, being careful to allow
+ the handler to remove itself when called */
+ for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
+ uint16_t flags = 0;
+
+ if (FD_ISSET(fde->fd, &r_fds)) flags |= TEVENT_FD_READ;
+ if (FD_ISSET(fde->fd, &w_fds)) flags |= TEVENT_FD_WRITE;
+ if (flags) {
+ fde->handler(std_ev->ev, fde, flags, fde->private_data);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ do a single event loop using the events defined in ev
+*/
+static int std_event_loop_once(struct tevent_context *ev, const char *location)
+{
+ struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
+ struct std_event_context);
+ struct timeval tval;
+
+ if (ev->signal_events &&
+ tevent_common_check_signal(ev)) {
+ return 0;
+ }
+
+ if (ev->immediate_events &&
+ tevent_common_loop_immediate(ev)) {
+ return 0;
+ }
+
+ tval = tevent_common_loop_timer_delay(ev);
+ if (tevent_timeval_is_zero(&tval)) {
+ return 0;
+ }
+
+ epoll_check_reopen(std_ev);
+
+ if (epoll_event_loop(std_ev, &tval) == 0) {
+ return 0;
+ }
+
+ return std_event_loop_select(std_ev, &tval);
+}
+
+static const struct tevent_ops std_event_ops = {
+ .context_init = std_event_context_init,
+ .add_fd = std_event_add_fd,
+ .set_fd_close_fn = tevent_common_fd_set_close_fn,
+ .get_fd_flags = tevent_common_fd_get_flags,
+ .set_fd_flags = std_event_set_fd_flags,
+ .add_timer = tevent_common_add_timer,
+ .schedule_immediate = tevent_common_schedule_immediate,
+ .add_signal = tevent_common_add_signal,
+ .loop_once = std_event_loop_once,
+ .loop_wait = tevent_common_loop_wait,
+};
+
+
+bool tevent_standard_init(void)
+{
+ return tevent_register_backend("standard", &std_event_ops);
+}
+
--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+
+ common events code for timed events
+
+ Copyright (C) Andrew Tridgell 2003-2006
+ Copyright (C) Stefan Metzmacher 2005-2009
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <atalk/tevent.h>
+
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+/**
+ compare two timeval structures.
+ Return -1 if tv1 < tv2
+ Return 0 if tv1 == tv2
+ Return 1 if tv1 > tv2
+*/
+int tevent_timeval_compare(const struct timeval *tv1, const struct timeval *tv2)
+{
+ if (tv1->tv_sec > tv2->tv_sec) return 1;
+ if (tv1->tv_sec < tv2->tv_sec) return -1;
+ if (tv1->tv_usec > tv2->tv_usec) return 1;
+ if (tv1->tv_usec < tv2->tv_usec) return -1;
+ return 0;
+}
+
+/**
+ return a zero timeval
+*/
+struct timeval tevent_timeval_zero(void)
+{
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ return tv;
+}
+
+/**
+ return a timeval for the current time
+*/
+struct timeval tevent_timeval_current(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv;
+}
+
+/**
+ return a timeval struct with the given elements
+*/
+struct timeval tevent_timeval_set(uint32_t secs, uint32_t usecs)
+{
+ struct timeval tv;
+ tv.tv_sec = secs;
+ tv.tv_usec = usecs;
+ return tv;
+}
+
+/**
+ return the difference between two timevals as a timeval
+ if tv1 comes after tv2, then return a zero timeval
+ (this is *tv2 - *tv1)
+*/
+struct timeval tevent_timeval_until(const struct timeval *tv1,
+ const struct timeval *tv2)
+{
+ struct timeval t;
+ if (tevent_timeval_compare(tv1, tv2) >= 0) {
+ return tevent_timeval_zero();
+ }
+ t.tv_sec = tv2->tv_sec - tv1->tv_sec;
+ if (tv1->tv_usec > tv2->tv_usec) {
+ t.tv_sec--;
+ t.tv_usec = 1000000 - (tv1->tv_usec - tv2->tv_usec);
+ } else {
+ t.tv_usec = tv2->tv_usec - tv1->tv_usec;
+ }
+ return t;
+}
+
+/**
+ return true if a timeval is zero
+*/
+bool tevent_timeval_is_zero(const struct timeval *tv)
+{
+ return tv->tv_sec == 0 && tv->tv_usec == 0;
+}
+
+struct timeval tevent_timeval_add(const struct timeval *tv, uint32_t secs,
+ uint32_t usecs)
+{
+ struct timeval tv2 = *tv;
+ tv2.tv_sec += secs;
+ tv2.tv_usec += usecs;
+ tv2.tv_sec += tv2.tv_usec / 1000000;
+ tv2.tv_usec = tv2.tv_usec % 1000000;
+
+ return tv2;
+}
+
+/**
+ return a timeval in the future with a specified offset
+*/
+struct timeval tevent_timeval_current_ofs(uint32_t secs, uint32_t usecs)
+{
+ struct timeval tv = tevent_timeval_current();
+ return tevent_timeval_add(&tv, secs, usecs);
+}
+
+/*
+ destroy a timed event
+*/
+static int tevent_common_timed_destructor(struct tevent_timer *te)
+{
+ tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE,
+ "Destroying timer event %p \"%s\"\n",
+ te, te->handler_name);
+
+ if (te->event_ctx) {
+ DLIST_REMOVE(te->event_ctx->timer_events, te);
+ }
+
+ return 0;
+}
+
+static int tevent_common_timed_deny_destructor(struct tevent_timer *te)
+{
+ return -1;
+}
+
+/*
+ add a timed event
+ return NULL on failure (memory allocation error)
+*/
+struct tevent_timer *tevent_common_add_timer(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
+ struct timeval next_event,
+ tevent_timer_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ struct tevent_timer *te, *last_te, *cur_te;
+
+ te = talloc(mem_ctx?mem_ctx:ev, struct tevent_timer);
+ if (te == NULL) return NULL;
+
+ te->event_ctx = ev;
+ te->next_event = next_event;
+ te->handler = handler;
+ te->private_data = private_data;
+ te->handler_name = handler_name;
+ te->location = location;
+ te->additional_data = NULL;
+
+ /* keep the list ordered */
+ last_te = NULL;
+ for (cur_te = ev->timer_events; cur_te; cur_te = cur_te->next) {
+ /* if the new event comes before the current one break */
+ if (tevent_timeval_compare(&te->next_event, &cur_te->next_event) < 0) {
+ break;
+ }
+
+ last_te = cur_te;
+ }
+
+ DLIST_ADD_AFTER(ev->timer_events, te, last_te);
+
+ talloc_set_destructor(te, tevent_common_timed_destructor);
+
+ tevent_debug(ev, TEVENT_DEBUG_TRACE,
+ "Added timed event \"%s\": %p\n",
+ handler_name, te);
+ return te;
+}
+
+/*
+ do a single event loop using the events defined in ev
+
+ return the delay untill the next timed event,
+ or zero if a timed event was triggered
+*/
+struct timeval tevent_common_loop_timer_delay(struct tevent_context *ev)
+{
+ struct timeval current_time = tevent_timeval_zero();
+ struct tevent_timer *te = ev->timer_events;
+
+ if (!te) {
+ /* have a default tick time of 30 seconds. This guarantees
+ that code that uses its own timeout checking will be
+ able to proceeed eventually */
+ return tevent_timeval_set(30, 0);
+ }
+
+ /*
+ * work out the right timeout for the next timed event
+ *
+ * avoid the syscall to gettimeofday() if the timed event should
+ * be triggered directly
+ *
+ * if there's a delay till the next timed event, we're done
+ * with just returning the delay
+ */
+ if (!tevent_timeval_is_zero(&te->next_event)) {
+ struct timeval delay;
+
+ current_time = tevent_timeval_current();
+
+ delay = tevent_timeval_until(¤t_time, &te->next_event);
+ if (!tevent_timeval_is_zero(&delay)) {
+ return delay;
+ }
+ }
+
+ /*
+ * ok, we have a timed event that we'll process ...
+ */
+
+ /* deny the handler to free the event */
+ talloc_set_destructor(te, tevent_common_timed_deny_destructor);
+
+ /* We need to remove the timer from the list before calling the
+ * handler because in a semi-async inner event loop called from the
+ * handler we don't want to come across this event again -- vl */
+ DLIST_REMOVE(ev->timer_events, te);
+
+ /*
+ * If the timed event was registered for a zero current_time,
+ * then we pass a zero timeval here too! To avoid the
+ * overhead of gettimeofday() calls.
+ *
+ * otherwise we pass the current time
+ */
+ te->handler(ev, te, current_time, te->private_data);
+
+ /* The destructor isn't necessary anymore, we've already removed the
+ * event from the list. */
+ talloc_set_destructor(te, NULL);
+
+ tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE,
+ "Ending timer event %p \"%s\"\n",
+ te, te->handler_name);
+
+ talloc_free(te);
+
+ return tevent_timeval_zero();
+}
+
--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Jelmer Vernooij 2005
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <atalk/tevent.h>
+#include <atalk/talloc.h>
+
+#include "tevent_internal.h"
+#include "tevent_util.h"
+#include <fcntl.h>
+
+/**
+ return the number of elements in a string list
+*/
+size_t ev_str_list_length(const char **list)
+{
+ size_t ret;
+ for (ret=0;list && list[ret];ret++) /* noop */ ;
+ return ret;
+}
+
+/**
+ add an entry to a string list
+*/
+const char **ev_str_list_add(const char **list, const char *s)
+{
+ size_t len = ev_str_list_length(list);
+ const char **ret;
+
+ ret = talloc_realloc(NULL, list, const char *, len+2);
+ if (ret == NULL) return NULL;
+
+ ret[len] = talloc_strdup(ret, s);
+ if (ret[len] == NULL) return NULL;
+
+ ret[len+1] = NULL;
+
+ return ret;
+}
+
+
+/**
+ Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
+ else
+ if SYSV use O_NDELAY
+ if BSD use FNDELAY
+**/
+
+int ev_set_blocking(int fd, bool set)
+{
+ int val;
+#ifdef O_NONBLOCK
+#define FLAG_TO_SET O_NONBLOCK
+#else
+#ifdef SYSV
+#define FLAG_TO_SET O_NDELAY
+#else /* BSD */
+#define FLAG_TO_SET FNDELAY
+#endif
+#endif
+
+ if((val = fcntl(fd, F_GETFL, 0)) == -1)
+ return -1;
+ if(set) /* Turn blocking on - ie. clear nonblock flag */
+ val &= ~FLAG_TO_SET;
+ else
+ val |= FLAG_TO_SET;
+ return fcntl( fd, F_SETFL, val);
+#undef FLAG_TO_SET
+}
--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 1998-2005
+ Copyright (C) Jelmer Vernooij 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* To use these macros you must have a structure containing a next and
+ prev pointer */
+
+#ifndef _DLINKLIST_H
+#define _DLINKLIST_H
+
+
+/* hook into the front of the list */
+#define DLIST_ADD(list, p) \
+do { \
+ if (!(list)) { \
+ (list) = (p); \
+ (p)->next = (p)->prev = NULL; \
+ } else { \
+ (list)->prev = (p); \
+ (p)->next = (list); \
+ (p)->prev = NULL; \
+ (list) = (p); \
+ }\
+} while (0)
+
+/* remove an element from a list - element doesn't have to be in list. */
+#define DLIST_REMOVE(list, p) \
+do { \
+ if ((p) == (list)) { \
+ (list) = (p)->next; \
+ if (list) (list)->prev = NULL; \
+ } else { \
+ if ((p)->prev) (p)->prev->next = (p)->next; \
+ if ((p)->next) (p)->next->prev = (p)->prev; \
+ } \
+ if ((p) != (list)) (p)->next = (p)->prev = NULL; \
+} while (0)
+
+/* promote an element to the top of the list */
+#define DLIST_PROMOTE(list, p) \
+do { \
+ DLIST_REMOVE(list, p); \
+ DLIST_ADD(list, p); \
+} while (0)
+
+/* hook into the end of the list - needs a tmp pointer */
+#define DLIST_ADD_END(list, p, type) \
+do { \
+ if (!(list)) { \
+ (list) = (p); \
+ (p)->next = (p)->prev = NULL; \
+ } else { \
+ type tmp; \
+ for (tmp = (list); tmp->next; tmp = tmp->next) ; \
+ tmp->next = (p); \
+ (p)->next = NULL; \
+ (p)->prev = tmp; \
+ } \
+} while (0)
+
+/* insert 'p' after the given element 'el' in a list. If el is NULL then
+ this is the same as a DLIST_ADD() */
+#define DLIST_ADD_AFTER(list, p, el) \
+do { \
+ if (!(list) || !(el)) { \
+ DLIST_ADD(list, p); \
+ } else { \
+ p->prev = el; \
+ p->next = el->next; \
+ el->next = p; \
+ if (p->next) p->next->prev = p; \
+ }\
+} while (0)
+
+/* demote an element to the end of the list, needs a tmp pointer */
+#define DLIST_DEMOTE(list, p, tmp) \
+do { \
+ DLIST_REMOVE(list, p); \
+ DLIST_ADD_END(list, p, tmp); \
+} while (0)
+
+/* concatenate two lists - putting all elements of the 2nd list at the
+ end of the first list */
+#define DLIST_CONCATENATE(list1, list2, type) \
+do { \
+ if (!(list1)) { \
+ (list1) = (list2); \
+ } else { \
+ type tmp; \
+ for (tmp = (list1); tmp->next; tmp = tmp->next) ; \
+ tmp->next = (list2); \
+ if (list2) { \
+ (list2)->prev = tmp; \
+ } \
+ } \
+} while (0)
+
+#endif /* _DLINKLIST_H */
+
+const char **ev_str_list_add(const char **list, const char *s);
+int ev_set_blocking(int fd, bool set);
+size_t ev_str_list_length(const char **list);
+
+/* Defined here so we can build against older talloc versions that don't
+ * have this define yet. */
+#ifndef TALLOC_FREE
+#define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
+#endif
--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+ Infrastructure for async requests
+ Copyright (C) Volker Lendecke 2008
+ Copyright (C) Stefan Metzmacher 2009
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <atalk/tevent.h>
+
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+struct tevent_wakeup_state {
+ struct timeval wakeup_time;
+};
+
+struct tevent_req *tevent_wakeup_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct timeval wakeup_time)
+{
+ struct tevent_req *req;
+ struct tevent_wakeup_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tevent_wakeup_state);
+ if (!req) {
+ return NULL;
+ }
+ state->wakeup_time = wakeup_time;
+
+ if (!tevent_req_set_endtime(req, ev, wakeup_time)) {
+ goto post;
+ }
+
+ return req;
+post:
+ return tevent_req_post(req, ev);
+}
+
+bool tevent_wakeup_recv(struct tevent_req *req)
+{
+ enum tevent_req_state state;
+ uint64_t error;
+
+ if (tevent_req_is_error(req, &state, &error)) {
+ if (state == TEVENT_REQ_TIMED_OUT) {
+ return true;
+ }
+ }
+
+ return false;
+}
+