Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package aml for openSUSE:Factory checked in at 2021-04-22 18:04:42 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/aml (Old) and /work/SRC/openSUSE:Factory/.aml.new.12324 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "aml" Thu Apr 22 18:04:42 2021 rev:3 rq:887812 version:0.2.0 Changes: -------- --- /work/SRC/openSUSE:Factory/aml/aml.changes 2020-09-25 16:33:21.363987401 +0200 +++ /work/SRC/openSUSE:Factory/.aml.new.12324/aml.changes 2021-04-22 18:06:18.110728166 +0200 @@ -1,0 +2,6 @@ +Tue Apr 13 23:18:38 UTC 2021 - Ferdinand Thiessen <[email protected]> + +- Update to 0.2.0 + * A kqueue backend has been added, run natively without epoll-shim + +------------------------------------------------------------------- Old: ---- aml-0.1.0.tar.gz New: ---- aml-0.2.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ aml.spec ++++++ --- /var/tmp/diff_new_pack.fnA6SM/_old 2021-04-22 18:06:18.578728941 +0200 +++ /var/tmp/diff_new_pack.fnA6SM/_new 2021-04-22 18:06:18.582728947 +0200 @@ -1,7 +1,7 @@ # # spec file for package aml # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2021 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,7 +17,7 @@ Name: aml -Version: 0.1.0 +Version: 0.2.0 Release: 0 Summary: Another Main Loop License: ISC ++++++ aml-0.1.0.tar.gz -> aml-0.2.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aml-0.1.0/include/aml.h new/aml-0.2.0/include/aml.h --- old/aml-0.1.0/include/aml.h 2020-07-26 13:17:06.000000000 +0200 +++ new/aml-0.2.0/include/aml.h 2020-12-31 13:37:18.000000000 +0100 @@ -17,6 +17,7 @@ #pragma once #include <stdint.h> +#include <stdbool.h> #include <unistd.h> struct aml; @@ -176,6 +177,12 @@ */ int aml_stop(struct aml*, void* obj); +/* Check if an event handler is started. + * + * Returns: true if it has been started, false otherwise. + */ +bool aml_is_started(struct aml*, void* obj); + /* Get the signal assigned to a signal handler. */ int aml_get_signo(const struct aml_signal* sig); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aml-0.1.0/include/backend.h new/aml-0.2.0/include/backend.h --- old/aml-0.1.0/include/backend.h 2020-07-26 13:17:06.000000000 +0200 +++ new/aml-0.2.0/include/backend.h 2020-12-31 13:37:18.000000000 +0100 @@ -31,6 +31,7 @@ struct aml_backend { uint32_t flags; + uint32_t clock; void* (*new_state)(struct aml*); void (*del_state)(void* state); int (*get_fd)(const void* state); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aml-0.1.0/meson.build new/aml-0.2.0/meson.build --- old/aml-0.1.0/meson.build 2020-07-26 13:17:06.000000000 +0200 +++ new/aml-0.2.0/meson.build 2020-12-31 13:37:18.000000000 +0100 @@ -1,7 +1,7 @@ project( 'aml', 'c', - version: '0.1.0', + version: '0.2.0', license: 'ISC', default_options: [ 'c_std=c11', @@ -9,6 +9,8 @@ ) buildtype = get_option('buildtype') +default_library = get_option('default_library') +is_static_subproject = meson.is_subproject() and default_library == 'static' c_args = [ '-DPROJECT_VERSION="@0@"'.format(meson.project_version()), @@ -37,7 +39,6 @@ cc = meson.get_compiler('c') -libepoll = dependency('epoll-shim', required: false) librt = cc.find_library('rt', required: true) threads = dependency('threads') @@ -45,12 +46,23 @@ sources = [ 'src/aml.c', - 'src/epoll.c', 'src/thread-pool.c', ] +have_epoll = cc.has_header_symbol('sys/epoll.h', 'epoll_create') +have_kqueue = cc.has_header_symbol('sys/event.h', 'kqueue') + +if have_epoll + sources += 'src/epoll.c' + message('epoll backend chosen') +elif have_kqueue + sources += 'src/kqueue.c' + message('kqueue backend chosen') +else + error('Unsupported system') +endif + dependencies = [ - libepoll, librt, threads, ] @@ -61,7 +73,7 @@ version: '0.0.0', dependencies: dependencies, include_directories: inc, - install: true, + install: not is_static_subproject, ) aml_dep = declare_dependency( @@ -73,13 +85,15 @@ subdir('examples') endif -install_headers('include/aml.h') +if not is_static_subproject + install_headers('include/aml.h') -pkgconfig = import('pkgconfig') -pkgconfig.generate( - libraries: aml, - version: meson.project_version(), - filebase: meson.project_name(), - name: meson.project_name(), - description: 'Amother main loop library', -) + pkgconfig = import('pkgconfig') + pkgconfig.generate( + aml, + version: meson.project_version(), + filebase: meson.project_name(), + name: meson.project_name(), + description: 'Another main loop library', + ) +endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aml-0.1.0/src/aml.c new/aml-0.2.0/src/aml.c --- old/aml-0.1.0/src/aml.c 2020-07-26 13:17:06.000000000 +0200 +++ new/aml-0.2.0/src/aml.c 2020-12-31 13:37:18.000000000 +0100 @@ -141,7 +141,7 @@ // TODO: Properly initialise this? static pthread_mutex_t aml__ref_mutex; -extern struct aml_backend epoll_backend; +extern struct aml_backend implementation; static struct aml_timer* aml__get_timer_with_earliest_deadline(struct aml* self); @@ -206,10 +206,10 @@ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); } -static uint64_t gettime_ms(void) +static uint64_t aml__gettime_ms(struct aml* self) { struct timespec ts = { 0 }; - clock_gettime(CLOCK_MONOTONIC, &ts); + clock_gettime(self->backend.clock, &ts); return ts.tv_sec * 1000ULL + ts.tv_nsec / 1000000ULL; } @@ -311,7 +311,7 @@ pthread_mutex_init(&self->obj_list_mutex, NULL); pthread_mutex_init(&self->timer_list_mutex, NULL); - memcpy(&self->backend, &epoll_backend, sizeof(self->backend)); + memcpy(&self->backend, &implementation, sizeof(self->backend)); if (!self->backend.thread_pool_acquire) self->backend.thread_pool_acquire = thread_pool_acquire_default; @@ -484,6 +484,15 @@ return false; } +EXPORT +bool aml_is_started(struct aml* self, void* obj) +{ + pthread_mutex_lock(&self->obj_list_mutex); + bool result = aml__obj_is_started_unlocked(self, obj); + pthread_mutex_unlock(&self->obj_list_mutex); + return result; +} + static int aml__obj_try_add(struct aml* self, void* obj) { int rc = -1; @@ -542,7 +551,7 @@ static int aml__start_timer(struct aml* self, struct aml_timer* timer) { - timer->deadline = gettime_ms() + timer->timeout; + timer->deadline = aml__gettime_ms(self) + timer->timeout; pthread_mutex_lock(&self->timer_list_mutex); LIST_INSERT_HEAD(&self->timer_list, timer, link); @@ -769,7 +778,7 @@ EXPORT void aml_dispatch(struct aml* self) { - uint64_t now = gettime_ms(); + uint64_t now = aml__gettime_ms(self); while (aml__handle_timeout(self, now)); struct aml_timer* earliest = aml__get_timer_with_earliest_deadline(self); @@ -1014,7 +1023,7 @@ { handler->event_mask = mask; - if (handler->parent) + if (handler->parent && aml_is_started(handler->parent, handler)) aml__mod_fd(handler->parent, handler); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aml-0.1.0/src/epoll.c new/aml-0.2.0/src/epoll.c --- old/aml-0.1.0/src/epoll.c 2020-07-26 13:17:06.000000000 +0200 +++ new/aml-0.2.0/src/epoll.c 2020-12-31 13:37:18.000000000 +0100 @@ -256,9 +256,10 @@ return timerfd_settime(self->timer_fd, TFD_TIMER_ABSTIME, &it, NULL); } -const struct aml_backend epoll_backend = { +const struct aml_backend implementation = { .new_state = epoll_new_state, .del_state = epoll_del_state, + .clock = CLOCK_MONOTONIC, .get_fd = epoll_get_fd, .poll = epoll_poll, .add_fd = epoll_add_fd, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aml-0.1.0/src/kqueue.c new/aml-0.2.0/src/kqueue.c --- old/aml-0.1.0/src/kqueue.c 1970-01-01 01:00:00.000000000 +0100 +++ new/aml-0.2.0/src/kqueue.c 2020-12-31 13:37:18.000000000 +0100 @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2020 Andri Yngvason + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "aml.h" +#include "backend.h" + +#include <sys/event.h> +#include <stdlib.h> +#include <unistd.h> +#include <time.h> +#include <pthread.h> +#include <signal.h> +#include <assert.h> + +struct kq_state { + struct aml* aml; + int fd; +}; + +static void* kq_new_state(struct aml* aml) +{ + struct kq_state* self = calloc(1, sizeof(*self)); + if (!self) + return NULL; + + self->aml = aml; + + self->fd = kqueue(); + if (self->fd < 0) + goto kqueue_failure; + + return self; + +kqueue_failure: + free(self); + return NULL; +} + +static void kq_del_state(void* state) +{ + struct kq_state* self = state; + close(self->fd); + free(self); +} + +static int kq_get_fd(const void* state) +{ + const struct kq_state* self = state; + return self->fd; +} + +static void kq_emit_event(struct kq_state* self, struct kevent* event) +{ + // TODO: Maybe joint read/write into one for fds? + switch (event->filter) { + case EVFILT_READ: + aml_emit(self->aml, event->udata, AML_EVENT_READ); + break; + case EVFILT_WRITE: + aml_emit(self->aml, event->udata, AML_EVENT_WRITE); + break; + case EVFILT_SIGNAL: + aml_emit(self->aml, event->udata, 0); + break; + case EVFILT_TIMER: + assert(event->ident == 0); + break; + } +} + +static int kq_poll(void* state, int timeout) +{ + struct kq_state* self = state; + + struct timespec ts = { + .tv_sec = timeout / 1000UL, + .tv_nsec = (timeout % 1000UL) * 1000000UL, + }; + + struct kevent events[16]; + size_t max_events = sizeof(events) / sizeof(events[0]); + + int nfds = kevent(self->fd, NULL, 0, events, max_events, &ts); + for (int i = 0; i < nfds; ++i) + kq_emit_event(self, &events[i]); + + return nfds; +} + +static int kq_add_fd(void* state, struct aml_handler* handler) +{ + struct kq_state* self = state; + int fd = aml_get_fd(handler); + + enum aml_event last_mask = (intptr_t)aml_get_backend_data(handler); + enum aml_event mask = aml_get_event_mask(handler); + aml_set_backend_data(handler, (void*)(intptr_t)mask); + + struct kevent events[2]; + int n = 0; + + if ((mask ^ last_mask) & AML_EVENT_READ) + EV_SET(&events[n++], fd, EVFILT_READ, + mask & AML_EVENT_READ ? EV_ADD : EV_DELETE, + 0, 0, handler); + + if ((mask ^ last_mask) & AML_EVENT_WRITE) + EV_SET(&events[n++], fd, EVFILT_WRITE, + mask & AML_EVENT_WRITE ? EV_ADD : EV_DELETE, + 0, 0, handler); + + return kevent(self->fd, events, n, NULL, 0, NULL); +} + +static int kq_del_fd(void* state, struct aml_handler* handler) +{ + struct kq_state* self = state; + int fd = aml_get_fd(handler); + + enum aml_event last_mask = (intptr_t)aml_get_backend_data(handler); + + struct kevent events[2]; + int n = 0; + + if (last_mask & AML_EVENT_READ) + EV_SET(&events[n++], fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); + + if (last_mask & AML_EVENT_WRITE) + EV_SET(&events[n++], fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); + + return kevent(self->fd, events, n, NULL, 0, NULL); +} + +static int kq_add_signal(void* state, struct aml_signal* sig) +{ + struct kq_state* self = state; + int signo = aml_get_signo(sig); + + struct kevent event; + EV_SET(&event, signo, EVFILT_SIGNAL, EV_ADD, 0, 0, sig); + + int rc = kevent(self->fd, &event, 1, NULL, 0, NULL); + + sigset_t ss; + sigemptyset(&ss); + sigaddset(&ss, signo); + pthread_sigmask(SIG_BLOCK, &ss, NULL); + + return rc; +} + +static int kq_del_signal(void* state, struct aml_signal* sig) +{ + struct kq_state* self = state; + int signo = aml_get_signo(sig); + + struct kevent event; + EV_SET(&event, signo, EVFILT_SIGNAL, EV_DELETE, 0, 0, NULL); + + // TODO: Restore signal mask + + return kevent(self->fd, &event, 1, NULL, 0, NULL); +} + +static int kq_set_deadline(void* state, uint64_t deadline) +{ + struct kq_state* self = state; + + struct kevent event; + EV_SET(&event, 0, EVFILT_TIMER, EV_ADD | EV_ONESHOT, + NOTE_MSECONDS | NOTE_ABSTIME, deadline, NULL); + + return kevent(self->fd, &event, 1, NULL, 0, NULL); +} + +const struct aml_backend implementation = { + .new_state = kq_new_state, + .del_state = kq_del_state, + .clock = CLOCK_REALTIME, + .get_fd = kq_get_fd, + .poll = kq_poll, + .add_fd = kq_add_fd, + .mod_fd = kq_add_fd, // Same as add_fd + .del_fd = kq_del_fd, + .add_signal = kq_add_signal, + .del_signal = kq_del_signal, + .set_deadline = kq_set_deadline, +};
