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 2 of the License, or
+ 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,
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, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
this is a very strange beast. The Linux AIO implementation doesn't
this is _very_ experimental code
*/
-#include "includes.h"
#include "system/filesys.h"
-#include "lib/util/dlinklist.h"
-#include "lib/events/events.h"
-#include "lib/events/events_internal.h"
+#include "replace.h"
+#include "events.h"
+#include "events_internal.h"
+#include "events_util.h"
#include <sys/epoll.h>
#include <libaio.h>
/* a pointer back to the generic event_context */
struct event_context *ev;
+ /* list of filedescriptor events */
+ struct fd_event *fd_events;
+
/* number of registered fd event handlers */
int num_fd_events;
int epoll_fd;
int is_epoll_set;
+ pid_t pid;
};
struct aio_event {
return 0;
}
+static void epoll_add_event(struct aio_event_context *aio_ev, struct fd_event *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 aio_event_context *aio_ev)
+{
+ struct fd_event *fde;
+
+ if (aio_ev->pid == getpid()) {
+ return;
+ }
+
+ close(aio_ev->epoll_fd);
+ aio_ev->epoll_fd = epoll_create(MAX_AIO_QUEUE_DEPTH);
+ if (aio_ev->epoll_fd == -1) {
+ ev_debug(aio_ev->ev, EV_DEBUG_FATAL, "Failed to recreate epoll handle after fork\n");
+ return;
+ }
+ aio_ev->pid = getpid();
+ for (fde=aio_ev->fd_events;fde;fde=fde->next) {
+ epoll_add_event(aio_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)
/* if we don't want events yet, don't add an aio_event */
if (fde->flags == 0) return;
- ZERO_STRUCT(event);
+ memset(&event, 0, sizeof(event));
event.events = epoll_map_flags(fde->flags);
event.data.ptr = fde;
epoll_ctl(aio_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event);
static void epoll_del_event(struct aio_event_context *aio_ev, struct fd_event *fde)
{
struct epoll_event event;
+
+ DLIST_REMOVE(aio_ev->fd_events, fde);
+
if (aio_ev->epoll_fd == -1) return;
fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
static void epoll_change_event(struct aio_event_context *aio_ev, struct fd_event *fde)
{
- BOOL got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
- BOOL want_read = (fde->flags & EVENT_FD_READ);
- BOOL want_write= (fde->flags & EVENT_FD_WRITE);
+ bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
+ bool want_read = (fde->flags & EVENT_FD_READ);
+ bool want_write= (fde->flags & EVENT_FD_WRITE);
if (aio_ev->epoll_fd == -1) return;
/* there's no aio_event attached to the fde */
if (want_read || (want_write && !got_error)) {
+ DLIST_ADD(aio_ev->fd_events, fde);
epoll_add_event(aio_ev, fde);
return;
}
static int aio_event_loop(struct aio_event_context *aio_ev, struct timeval *tvalp)
{
int ret, i;
- uint32_t destruction_count = aio_ev->destruction_count;
+ uint32_t destruction_count = ++aio_ev->destruction_count;
struct timespec timeout;
struct io_event events[8];
}
if (ret == 0 && tvalp) {
- common_event_loop_timer(aio_ev->ev);
+ /* we don't care about a possible delay here */
+ common_event_loop_timer_delay(aio_ev->ev);
return 0;
}
aio_ev->epoll_iocb = talloc(aio_ev, struct iocb);
if (io_queue_init(MAX_AIO_QUEUE_DEPTH, &aio_ev->ioctx) != 0) {
+ talloc_free(aio_ev);
return -1;
}
aio_ev->epoll_fd = epoll_create(MAX_AIO_QUEUE_DEPTH);
- if (aio_ev->epoll_fd == -1) return -1;
+ if (aio_ev->epoll_fd == -1) {
+ talloc_free(aio_ev);
+ return -1;
+ }
+ aio_ev->pid = getpid();
talloc_set_destructor(aio_ev, aio_ctx_destructor);
ev->additional_data = aio_ev;
+
+ if (setup_epoll_wait(aio_ev) < 0) {
+ talloc_free(aio_ev);
+ return -1;
+ }
+
return 0;
}
struct aio_event_context *aio_ev = talloc_get_type(ev->additional_data,
struct aio_event_context);
+ epoll_check_reopen(aio_ev);
+
aio_ev->num_fd_events--;
aio_ev->destruction_count++;
epoll_del_event(aio_ev, fde);
+ if (fde->flags & EVENT_FD_AUTOCLOSE) {
+ close(fde->fd);
+ fde->fd = -1;
+ }
+
return 0;
}
struct aio_event_context);
struct fd_event *fde;
+ epoll_check_reopen(aio_ev);
+
fde = talloc(mem_ctx?mem_ctx:ev, struct fd_event);
if (!fde) return NULL;
aio_ev->num_fd_events++;
talloc_set_destructor(fde, aio_event_fd_destructor);
+ DLIST_ADD(aio_ev->fd_events, fde);
epoll_add_event(aio_ev, fde);
return fde;
fde->flags = flags;
+ epoll_check_reopen(aio_ev);
+
epoll_change_event(aio_ev, fde);
}
struct aio_event_context);
struct timeval tval;
- tval = common_event_loop_delay(ev);
-
- if (timeval_is_zero(&tval)) {
- common_event_loop_timer(ev);
+ tval = common_event_loop_timer_delay(ev);
+ if (ev_timeval_is_zero(&tval)) {
return 0;
}
+ epoll_check_reopen(aio_ev);
+
return aio_event_loop(aio_ev, &tval);
}
.loop_wait = aio_event_loop_wait,
};
-NTSTATUS events_aio_init(void)
+bool events_aio_init(void)
{
return event_register_backend("aio", &aio_event_ops);
}
+