Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package aml for openSUSE:Factory checked in at 2026-04-28 16:39:59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/aml (Old) and /work/SRC/openSUSE:Factory/.aml.new.11940 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "aml" Tue Apr 28 16:39:59 2026 rev:7 rq:1349766 version:1.0.0 Changes: -------- --- /work/SRC/openSUSE:Factory/aml/aml.changes 2023-01-28 18:47:20.323297746 +0100 +++ /work/SRC/openSUSE:Factory/.aml.new.11940/aml.changes 2026-04-28 16:40:02.970674897 +0200 @@ -1,0 +2,6 @@ +Tue Apr 28 11:11:21 UTC 2026 - Michael Vetter <[email protected]> + +- Update to 1.0.0: + * This release improves type safety and does away with opaque void* objects + +------------------------------------------------------------------- Old: ---- aml-0.3.0.tar.gz New: ---- aml-1.0.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ aml.spec ++++++ --- /var/tmp/diff_new_pack.NajFTO/_old 2026-04-28 16:40:03.766707817 +0200 +++ /var/tmp/diff_new_pack.NajFTO/_new 2026-04-28 16:40:03.770707982 +0200 @@ -1,7 +1,7 @@ # # spec file for package aml # -# Copyright (c) 2023 SUSE LLC +# Copyright (c) 2026 SUSE LLC and contributors # # 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.3.0 +Version: 1.0.0 Release: 0 Summary: Another Main Loop License: ISC @@ -32,16 +32,16 @@ %package devel Summary: Development files for %{name} Group: Development/Libraries/C and C++ -Requires: libaml0 = %{version} +Requires: libaml1 = %{version} %description devel Development files and headers for %{name}. -%package -n libaml0 +%package -n libaml1 Summary: A VNC server library Group: System/Libraries -%description -n libaml0 +%description -n libaml1 A portable, uitlitarian and simple event loop library. %prep @@ -55,18 +55,18 @@ %install %meson_install -%post -n libaml0 -p /sbin/ldconfig -%postun -n libaml0 -p /sbin/ldconfig +%post -n libaml1 -p /sbin/ldconfig +%postun -n libaml1 -p /sbin/ldconfig %files devel %license COPYING %doc README.md - -%{_includedir}/aml.h +%dir %{_includedir}/aml1 +%{_includedir}/aml1/aml.h %{_libdir}/libaml.so -%{_libdir}/pkgconfig/aml.pc +%{_libdir}/pkgconfig/aml1.pc -%files -n libaml0 -%{_libdir}/libaml.so.0 -%{_libdir}/libaml.so.0.0.0 +%files -n libaml1 +%{_libdir}/libaml.so.1 +%{_libdir}/libaml.so.1.0.0 ++++++ aml-0.3.0.tar.gz -> aml-1.0.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aml-0.3.0/FUNDING.yml new/aml-1.0.0/FUNDING.yml --- old/aml-0.3.0/FUNDING.yml 2023-01-22 13:57:53.000000000 +0100 +++ new/aml-1.0.0/FUNDING.yml 2025-07-27 14:59:38.000000000 +0200 @@ -1 +1,2 @@ +github: any1 patreon: andriyngvason diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aml-0.3.0/examples/nested-ticker.c new/aml-1.0.0/examples/nested-ticker.c --- old/aml-0.3.0/examples/nested-ticker.c 2023-01-22 13:57:53.000000000 +0100 +++ new/aml-1.0.0/examples/nested-ticker.c 2025-07-27 14:59:38.000000000 +0200 @@ -6,7 +6,7 @@ static int do_exit = 0; -static void on_tick(void* ticker) +static void on_tick(struct aml_ticker* ticker) { int* count_ptr = aml_get_userdata(ticker); @@ -18,7 +18,7 @@ aml_exit(aml_get_default()); } -static void on_sigint(void* sig) +static void on_sigint(struct aml_signal* sig) { do_exit = 1; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aml-0.3.0/examples/reader.c new/aml-1.0.0/examples/reader.c --- old/aml-0.3.0/examples/reader.c 2023-01-22 13:57:53.000000000 +0100 +++ new/aml-1.0.0/examples/reader.c 2025-07-27 14:59:38.000000000 +0200 @@ -19,7 +19,7 @@ #include <aml.h> #include <signal.h> -static void on_line(void* handler) +static void on_line(struct aml_handler* handler) { char line[256]; fscanf(stdin, "%s", line); @@ -30,7 +30,7 @@ aml_exit(aml_get_default()); } -static void on_sigint(void* sig) +static void on_sigint(struct aml_signal* sig) { aml_exit(aml_get_default()); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aml-0.3.0/examples/ticker.c new/aml-1.0.0/examples/ticker.c --- old/aml-0.3.0/examples/ticker.c 2023-01-22 13:57:53.000000000 +0100 +++ new/aml-1.0.0/examples/ticker.c 2025-07-27 14:59:38.000000000 +0200 @@ -2,7 +2,7 @@ #include <aml.h> #include <signal.h> -static void on_tick(void* ticker) +static void on_tick(struct aml_ticker* ticker) { int* count_ptr = aml_get_userdata(ticker); @@ -14,7 +14,7 @@ aml_exit(aml_get_default()); } -static void on_sigint(void* sig) +static void on_sigint(struct aml_signal* sig) { aml_exit(aml_get_default()); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aml-0.3.0/include/aml.h new/aml-1.0.0/include/aml.h --- old/aml-0.3.0/include/aml.h 2023-01-22 13:57:53.000000000 +0100 +++ new/aml-1.0.0/include/aml.h 2025-07-27 14:59:38.000000000 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2022 Andri Yngvason + * Copyright (c) 2020 - 2024 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 @@ -16,21 +16,96 @@ #pragma once -#ifndef AML_UNSTABLE_API -#define AML_UNSTABLE_API 0 -#endif - -/* Something like this is necessary when changes are made that don't break the - * build but will cause nasty bugs if ignored. - */ -#if AML_UNSTABLE_API != 1 -#error "API has changed! Please, observe the changes and acknowledge by defining AML_UNSTABLE_API as 1 before including aml.h" -#endif - #include <stdint.h> #include <stdbool.h> #include <unistd.h> +#define aml_ref(obj) _Generic((obj), \ + struct aml*: aml_loop_ref, \ + struct aml_handler*: aml_handler_ref, \ + struct aml_timer*: aml_timer_ref, \ + struct aml_ticker*: aml_ticker_ref, \ + struct aml_signal*: aml_signal_ref, \ + struct aml_work*: aml_work_ref, \ + struct aml_idle*: aml_idle_ref \ + )(obj) + +#define aml_unref(obj) _Generic((obj), \ + struct aml*: aml_loop_unref, \ + struct aml_handler*: aml_handler_unref, \ + struct aml_timer*: aml_timer_unref, \ + struct aml_ticker*: aml_ticker_unref, \ + struct aml_signal*: aml_signal_unref, \ + struct aml_work*: aml_work_unref, \ + struct aml_idle*: aml_idle_unref \ + )(obj) + +#define aml_set_userdata(aml, obj) _Generic((obj), \ + struct aml*: aml_loop_set_userdata, \ + struct aml_handler*: aml_handler_set_userdata, \ + struct aml_timer*: aml_timer_set_userdata, \ + struct aml_ticker*: aml_ticker_set_userdata, \ + struct aml_signal*: aml_signal_set_userdata, \ + struct aml_work*: aml_work_set_userdata, \ + struct aml_idle*: aml_idle_set_userdata \ + )(aml, obj) + +#define aml_get_userdata(obj) _Generic((obj), \ + struct aml*: aml_loop_get_userdata, \ + const struct aml*: aml_loop_get_userdata, \ + struct aml_handler*: aml_handler_get_userdata, \ + const struct aml_handler*: aml_handler_get_userdata, \ + struct aml_timer*: aml_timer_get_userdata, \ + const struct aml_timer*: aml_timer_get_userdata, \ + struct aml_ticker*: aml_ticker_get_userdata, \ + const struct aml_ticker*: aml_ticker_get_userdata, \ + struct aml_signal*: aml_signal_get_userdata, \ + const struct aml_signal*: aml_signal_get_userdata, \ + struct aml_work*: aml_work_get_userdata, \ + const struct aml_work*: aml_work_get_userdata, \ + struct aml_idle*: aml_idle_get_userdata, \ + const struct aml_idle*: aml_idle_get_userdata \ + )(obj) + +#define aml_get_fd(obj) _Generic((obj), \ + struct aml*: aml_loop_get_fd, \ + const struct aml*: aml_loop_get_fd, \ + struct aml_handler*: aml_handler_get_fd, \ + const struct aml_handler*: aml_handler_get_fd \ + )(obj) + +#define aml_set_duration(obj, duration) _Generic((obj), \ + struct aml_timer*: aml_timer_set_duration, \ + struct aml_ticker*: aml_ticker_set_duration \ + )(obj, duration) + +#define aml_start(aml, obj) _Generic((obj), \ + struct aml_handler*: aml_start_handler, \ + struct aml_timer*: aml_start_timer, \ + struct aml_ticker*: aml_start_ticker, \ + struct aml_signal*: aml_start_signal, \ + struct aml_work*: aml_start_work, \ + struct aml_idle*: aml_start_idle \ + )(aml, obj) + +#define aml_stop(aml, obj) _Generic((obj), \ + struct aml_handler*: aml_stop_handler, \ + struct aml_timer*: aml_stop_timer, \ + struct aml_ticker*: aml_stop_ticker, \ + struct aml_signal*: aml_stop_signal, \ + struct aml_work*: aml_stop_work, \ + struct aml_idle*: aml_stop_idle \ + )(aml, obj) + +#define aml_is_started(aml, obj) _Generic((obj), \ + struct aml_handler*: aml_is_handler_started, \ + struct aml_timer*: aml_is_timer_started, \ + struct aml_ticker*: aml_is_ticker_started, \ + struct aml_signal*: aml_is_signal_started, \ + struct aml_work*: aml_is_work_started, \ + struct aml_idle*: aml_is_idle_started \ + )(aml, obj) + struct aml; struct aml_handler; struct aml_timer; @@ -46,11 +121,9 @@ AML_EVENT_OOB = 1 << 2, }; -typedef void (*aml_callback_fn)(void* obj); typedef void (*aml_free_fn)(void*); extern const char aml_version[]; -extern const int aml_unstable_abi_version; /* Create a new main loop instance */ struct aml* aml_new(void); @@ -96,53 +169,48 @@ * * Returns how many references there were BEFORE the call. */ -int aml_ref(void* obj); +int aml_loop_ref(struct aml* loop); +int aml_handler_ref(struct aml_handler* obj); +int aml_timer_ref(struct aml_timer* obj); +int aml_ticker_ref(struct aml_ticker* obj); +int aml_signal_ref(struct aml_signal* obj); +int aml_work_ref(struct aml_work* obj); +int aml_idle_ref(struct aml_idle* obj); /* Decrement the reference count by one. * * Returns how many references there are AFTER the call. */ -int aml_unref(void* obj); - -/* Create a new weak reference to the object. - * - * The reference object must be deleted using aml_weak_ref_del(). - */ -struct aml_weak_ref* aml_weak_ref_new(void* obj); - -/* Delete a weak reference created by aml_weak_ref_new(). - */ -void aml_weak_ref_del(struct aml_weak_ref* self); - -/* Try to get a new strong reference from a weak reference object. - * - * If the weak reference is still valid, the reference count on the returned - * aml object will be increased by one. Otherwise NULL is returned. - */ -void* aml_weak_ref_read(struct aml_weak_ref* self); +int aml_loop_unref(struct aml* loop); +int aml_handler_unref(struct aml_handler* obj); +int aml_timer_unref(struct aml_timer* obj); +int aml_ticker_unref(struct aml_ticker* obj); +int aml_signal_unref(struct aml_signal* obj); +int aml_work_unref(struct aml_work* obj); +int aml_idle_unref(struct aml_idle* obj); /* The following calls create event handler objects. * * An object will have a reference count of 1 upon creation and must be freed * using aml_unref(). */ -struct aml_handler* aml_handler_new(int fd, aml_callback_fn, void* userdata, - aml_free_fn); +struct aml_handler* aml_handler_new(int fd, void (*cb)(struct aml_handler*), + void* userdata, aml_free_fn); -struct aml_timer* aml_timer_new(uint64_t timeout, aml_callback_fn, - void* userdata, aml_free_fn); +struct aml_timer* aml_timer_new(uint64_t timeout, void (*cb)(struct aml_timer*), + void* userdata, aml_free_fn); -struct aml_ticker* aml_ticker_new(uint64_t period, aml_callback_fn, - void* userdata, aml_free_fn); +struct aml_ticker* aml_ticker_new(uint64_t period, void (*cb)(struct aml_ticker*), + void* userdata, aml_free_fn); -struct aml_signal* aml_signal_new(int signo, aml_callback_fn, - void* userdata, aml_free_fn); +struct aml_signal* aml_signal_new(int signo, void (*cb)(struct aml_signal*), + void* userdata, aml_free_fn); -struct aml_work* aml_work_new(aml_callback_fn work_fn, aml_callback_fn done_fn, - void* userdata, aml_free_fn); +struct aml_work* aml_work_new(void (*work_fn)(struct aml_work*), + void (*done_fn)(struct aml_work*), void* userdata, aml_free_fn); -struct aml_idle* aml_idle_new(aml_callback_fn done_fn, void* userdata, - aml_free_fn); +struct aml_idle* aml_idle_new(void (*cb)(struct aml_idle*), void* userdata, + aml_free_fn); /* Get the file descriptor associated with either a handler or the main loop. * @@ -152,15 +220,29 @@ * The fd returned from the main loop object can be used in other main loops to * monitor events on an aml main loop. */ -int aml_get_fd(const void* obj); +int aml_loop_get_fd(const struct aml* self); +int aml_handler_get_fd(const struct aml_handler* self); /* Associate random data with an object. * * If a free function is defined, it will be called to free the assigned * userdata when the object is freed as a result of aml_unref(). */ -void aml_set_userdata(void* obj, void* userdata, aml_free_fn); -void* aml_get_userdata(const void* obj); +void aml_loop_set_userdata(struct aml* obj, void* userdata, aml_free_fn); +void aml_handler_set_userdata(struct aml_handler* obj, void* userdata, aml_free_fn); +void aml_timer_set_userdata(struct aml_timer* obj, void* userdata, aml_free_fn); +void aml_ticker_set_userdata(struct aml_ticker* obj, void* userdata, aml_free_fn); +void aml_signal_set_userdata(struct aml_signal* obj, void* userdata, aml_free_fn); +void aml_work_set_userdata(struct aml_work* obj, void* userdata, aml_free_fn); +void aml_idle_set_userdata(struct aml_idle* obj, void* userdata, aml_free_fn); + +void* aml_loop_get_userdata(const struct aml* obj); +void* aml_handler_get_userdata(const struct aml_handler* obj); +void* aml_timer_get_userdata(const struct aml_timer* obj); +void* aml_ticker_get_userdata(const struct aml_ticker* obj); +void* aml_signal_get_userdata(const struct aml_signal* obj); +void* aml_work_get_userdata(const struct aml_work* obj); +void* aml_idle_get_userdata(const struct aml_idle* obj); void aml_set_event_mask(struct aml_handler* obj, enum aml_event mask); enum aml_event aml_get_event_mask(const struct aml_handler* obj); @@ -173,7 +255,8 @@ * * Calling this on a started timer/ticker yields undefined behaviour */ -void aml_set_duration(void* obj, uint64_t value); +void aml_timer_set_duration(struct aml_timer* self, uint64_t value); +void aml_ticker_set_duration(struct aml_ticker* self, uint64_t value); /* Start an event handler. * @@ -181,7 +264,12 @@ * * Returns: 0 on success, -1 if the handler is already started. */ -int aml_start(struct aml*, void* obj); +int aml_start_handler(struct aml*, struct aml_handler*); +int aml_start_timer(struct aml*, struct aml_timer*); +int aml_start_ticker(struct aml*, struct aml_ticker*); +int aml_start_signal(struct aml*, struct aml_signal*); +int aml_start_work(struct aml*, struct aml_work*); +int aml_start_idle(struct aml*, struct aml_idle*); /* Stop an event handler. * @@ -193,13 +281,23 @@ * * Returns: 0 on success, -1 if the handler is already stopped. */ -int aml_stop(struct aml*, void* obj); +int aml_stop_handler(struct aml*, struct aml_handler*); +int aml_stop_timer(struct aml*, struct aml_timer*); +int aml_stop_ticker(struct aml*, struct aml_ticker*); +int aml_stop_signal(struct aml*, struct aml_signal*); +int aml_stop_work(struct aml*, struct aml_work*); +int aml_stop_idle(struct aml*, struct aml_idle*); /* Check if an event handler is started. * * Returns: true if it has been started, false otherwise. */ -bool aml_is_started(struct aml*, void* obj); +bool aml_is_handler_started(struct aml*, struct aml_handler* obj); +bool aml_is_timer_started(struct aml*, struct aml_timer* obj); +bool aml_is_ticker_started(struct aml*, struct aml_ticker* obj); +bool aml_is_signal_started(struct aml*, struct aml_signal* obj); +bool aml_is_work_started(struct aml*, struct aml_work* obj); +bool aml_is_idle_started(struct aml*, struct aml_idle* obj); /* Get the signal assigned to a signal handler. */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aml-0.3.0/include/backend.h new/aml-1.0.0/include/backend.h --- old/aml-0.3.0/include/backend.h 2023-01-22 13:57:53.000000000 +0100 +++ new/aml-1.0.0/include/backend.h 2025-07-27 14:59:38.000000000 +0200 @@ -80,3 +80,20 @@ * returned, if it is greater, then the time until next event is returned. */ int aml_get_next_timeout(struct aml* self, int timeout); + +/* Create a new weak reference to the object. + * + * The reference object must be deleted using aml_weak_ref_del(). + */ +struct aml_weak_ref* aml_weak_ref_new(void* obj); + +/* Delete a weak reference created by aml_weak_ref_new(). + */ +void aml_weak_ref_del(struct aml_weak_ref* self); + +/* Try to get a new strong reference from a weak reference object. + * + * If the weak reference is still valid, the reference count on the returned + * aml object will be increased by one. Otherwise NULL is returned. + */ +void* aml_weak_ref_read(struct aml_weak_ref* self); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aml-0.3.0/include/sys/queue.h new/aml-1.0.0/include/sys/queue.h --- old/aml-0.3.0/include/sys/queue.h 2023-01-22 13:57:53.000000000 +0100 +++ new/aml-1.0.0/include/sys/queue.h 2025-07-27 14:59:38.000000000 +0200 @@ -35,8 +35,6 @@ #ifndef _SYS_QUEUE_H_ #define _SYS_QUEUE_H_ -#include <sys/cdefs.h> - /* * This file defines four types of data structures: singly-linked lists, * singly-linked tail queues, lists and tail queues. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aml-0.3.0/meson.build new/aml-1.0.0/meson.build --- old/aml-0.3.0/meson.build 2023-01-22 13:57:53.000000000 +0100 +++ new/aml-1.0.0/meson.build 2025-07-27 14:59:38.000000000 +0200 @@ -1,7 +1,7 @@ project( 'aml', 'c', - version: '0.3.0', + version: '1.0.0', license: 'ISC', default_options: [ 'c_std=c11', @@ -17,16 +17,16 @@ '-DPROJECT_VERSION="@0@"'.format(meson.project_version()), '-D_POSIX_C_SOURCE=200809L', '-fvisibility=hidden', - '-DAML_UNSTABLE_API=1', - '-Wmissing-prototypes', '-Wno-unused-parameter', ] git = find_program('git', native: true, required: false) if git.found() - git_describe = run_command([git, 'describe', '--tags', '--long']) - git_branch = run_command([git, 'rev-parse', '--abbrev-ref', 'HEAD']) + git_describe = run_command([git, 'describe', '--tags', '--long'], + check: false) + git_branch = run_command([git, 'rev-parse', '--abbrev-ref', 'HEAD'], + check: false) if git_describe.returncode() == 0 and git_branch.returncode() == 0 c_args += '-DGIT_VERSION="@0@ (@1@)"'.format( git_describe.stdout().strip(), @@ -43,7 +43,7 @@ cc = meson.get_compiler('c') -librt = cc.find_library('rt', required: true) +librt = cc.find_library('rt', required: false) threads = dependency('threads') inc = include_directories('include') @@ -74,7 +74,7 @@ aml = library( 'aml', sources, - version: '0.0.0', + version: '1.0.0', dependencies: dependencies, include_directories: inc, install: not is_static_subproject, @@ -90,13 +90,14 @@ endif if not is_static_subproject - install_headers('include/aml.h') + install_headers('include/aml.h', subdir: meson.project_name() + '1') pkgconfig = import('pkgconfig') pkgconfig.generate( aml, version: meson.project_version(), - filebase: meson.project_name(), + filebase: meson.project_name() + '1', + subdirs: meson.project_name() + '1', name: meson.project_name(), description: 'Another main loop library', ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aml-0.3.0/src/aml.c new/aml-1.0.0/src/aml.c --- old/aml-0.3.0/src/aml.c 2023-01-22 13:57:53.000000000 +0100 +++ new/aml-1.0.0/src/aml.c 2025-07-27 14:59:38.000000000 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2022 Andri Yngvason + * Copyright (c) 2020 - 2024 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 @@ -96,6 +96,16 @@ LIST_ENTRY(aml_timer) link; }; +struct aml_ticker { + struct aml_obj obj; + + uint64_t timeout; + uint64_t deadline; + bool expired; + + LIST_ENTRY(aml_timer) link; +}; + LIST_HEAD(aml_timer_list, aml_timer); struct aml_signal { @@ -144,8 +154,7 @@ static struct aml* aml__default = NULL; -// TODO: Properly initialise this? -static pthread_mutex_t aml__ref_mutex; +static pthread_mutex_t aml__ref_mutex = PTHREAD_MUTEX_INITIALIZER; extern struct aml_backend implementation; @@ -159,7 +168,7 @@ EXPORT const char aml_version[] = "UNKNOWN"; #endif -EXPORT const int aml_unstable_abi_version = AML_UNSTABLE_API; +static void aml__free(struct aml* self); EXPORT void aml_set_default(struct aml* aml) @@ -272,10 +281,101 @@ return obj; } -static void on_self_pipe_read(void* obj) { - struct aml* self = aml_get_userdata(obj); +static int aml_obj_ref(struct aml_obj* self) +{ + aml__ref_lock(); + assert(self->ref >= 0); + int ref = self->ref++; + aml__ref_unlock(); + return ref; +} + +static int aml_obj_unref(struct aml_obj* self) +{ + aml__ref_lock(); + int ref = --self->ref; + aml__ref_unlock(); + + assert(ref >= 0); + if (ref > 0) + goto done; + + aml__ref_lock(); + while (!LIST_EMPTY(&self->weak_refs)) { + struct aml_weak_ref* ref = LIST_FIRST(&self->weak_refs); + ref->obj = NULL; + LIST_REMOVE(ref, link); + } + aml__ref_unlock(); + + switch (self->type) { + case AML_OBJ_AML: + aml__free((struct aml*)self); + break; + case AML_OBJ_HANDLER: + case AML_OBJ_TIMER: + case AML_OBJ_TICKER: + case AML_OBJ_SIGNAL: + case AML_OBJ_WORK: + case AML_OBJ_IDLE: + if (self->free_fn) + self->free_fn(self->userdata); + free(self); + break; + default: + abort(); + break; + } + +done: + return ref; +} + +static void* aml_obj_get_userdata(const struct aml_obj* obj) +{ + return obj->userdata; +} + +static void aml_obj_set_userdata(struct aml_obj* obj, void* userdata, + aml_free_fn free_fn) +{ + obj->userdata = userdata; + obj->free_fn = free_fn; +} + +#define X(type, name) \ +EXPORT int aml_ ## name ## _ref(struct type* self) \ +{ \ + return aml_obj_ref(&self->obj); \ +} \ +EXPORT int aml_ ## name ## _unref(struct type* self) \ +{ \ + return aml_obj_unref(&self->obj); \ +} \ +EXPORT void aml_ ## name ## _set_userdata(struct type* self, void* ud, \ + aml_free_fn free_fn) \ +{ \ + aml_obj_set_userdata(&self->obj, ud, free_fn); \ +} \ +EXPORT void* aml_ ## name ## _get_userdata(const struct type* self) \ +{ \ + return aml_obj_get_userdata(&self->obj); \ +} + +X(aml, loop) +X(aml_handler, handler) +X(aml_timer, timer) +X(aml_ticker, ticker) +X(aml_signal, signal) +X(aml_work, work) +X(aml_idle, idle) + +#undef X + +static void on_self_pipe_read(struct aml_handler* handler) { + struct aml* self = aml_get_userdata(handler); assert(self); - assert(self->self_pipe_rfd == aml_get_fd(obj)); + assert(self->self_pipe_rfd == aml_get_fd(handler)); char dummy[256]; while (read(self->self_pipe_rfd, dummy, sizeof(dummy)) > 0); @@ -401,8 +501,9 @@ } EXPORT -struct aml_handler* aml_handler_new(int fd, aml_callback_fn callback, - void* userdata, aml_free_fn free_fn) +struct aml_handler* aml_handler_new(int fd, + void (*callback)(struct aml_handler*), void* userdata, + aml_free_fn free_fn) { struct aml_handler* self = calloc(1, sizeof(*self)); if (!self) @@ -412,7 +513,7 @@ self->obj.ref = 1; self->obj.userdata = userdata; self->obj.free_fn = free_fn; - self->obj.cb = callback; + self->obj.cb = (void*)callback; LIST_INIT(&self->obj.weak_refs); self->fd = fd; @@ -422,8 +523,9 @@ } EXPORT -struct aml_timer* aml_timer_new(uint64_t timeout, aml_callback_fn callback, - void* userdata, aml_free_fn free_fn) +struct aml_timer* aml_timer_new(uint64_t timeout, + void (*callback)(struct aml_timer*), void* userdata, + aml_free_fn free_fn) { struct aml_timer* self = calloc(1, sizeof(*self)); if (!self) @@ -433,7 +535,7 @@ self->obj.ref = 1; self->obj.userdata = userdata; self->obj.free_fn = free_fn; - self->obj.cb = callback; + self->obj.cb = (void*)callback; LIST_INIT(&self->obj.weak_refs); self->timeout = timeout; @@ -442,18 +544,20 @@ } EXPORT -struct aml_ticker* aml_ticker_new(uint64_t period, aml_callback_fn callback, - void* userdata, aml_free_fn free_fn) +struct aml_ticker* aml_ticker_new(uint64_t period, + void (*callback)(struct aml_ticker*), + void* userdata, aml_free_fn free_fn) { struct aml_timer* timer = - aml_timer_new(period, callback, userdata, free_fn); + aml_timer_new(period, (void*)callback, userdata, free_fn); timer->obj.type = AML_OBJ_TICKER; return (struct aml_ticker*)timer; } EXPORT -struct aml_signal* aml_signal_new(int signo, aml_callback_fn callback, - void* userdata, aml_free_fn free_fn) +struct aml_signal* aml_signal_new(int signo, + void (*callback)(struct aml_signal*), void* userdata, + aml_free_fn free_fn) { struct aml_signal* self = calloc(1, sizeof(*self)); if (!self) @@ -463,7 +567,7 @@ self->obj.ref = 1; self->obj.userdata = userdata; self->obj.free_fn = free_fn; - self->obj.cb = callback; + self->obj.cb = (void*)callback; LIST_INIT(&self->obj.weak_refs); self->signo = signo; @@ -472,8 +576,9 @@ } EXPORT -struct aml_work* aml_work_new(aml_callback_fn work_fn, aml_callback_fn callback, - void* userdata, aml_free_fn free_fn) +struct aml_work* aml_work_new(void (*work_fn)(struct aml_work*), + void (*callback)(struct aml_work*), void* userdata, + aml_free_fn free_fn) { struct aml_work* self = calloc(1, sizeof(*self)); if (!self) @@ -483,17 +588,17 @@ self->obj.ref = 1; self->obj.userdata = userdata; self->obj.free_fn = free_fn; - self->obj.cb = callback; + self->obj.cb = (void*)callback; LIST_INIT(&self->obj.weak_refs); - self->work_fn = work_fn; + self->work_fn = (void*)work_fn; return self; } EXPORT -struct aml_idle* aml_idle_new(aml_callback_fn callback, void* userdata, - aml_free_fn free_fn) +struct aml_idle* aml_idle_new(void (*callback)(struct aml_idle*), + void* userdata, aml_free_fn free_fn) { struct aml_idle* self = calloc(1, sizeof(*self)); if (!self) @@ -503,7 +608,7 @@ self->obj.ref = 1; self->obj.userdata = userdata; self->obj.free_fn = free_fn; - self->obj.cb = callback; + self->obj.cb = (void*)callback; LIST_INIT(&self->obj.weak_refs); return self; @@ -531,8 +636,7 @@ return false; } -EXPORT -bool aml_is_started(struct aml* self, void* obj) +static bool aml_is_obj_started(struct aml* self, struct aml_obj* obj) { pthread_mutex_lock(&self->obj_list_mutex); bool result = aml__obj_is_started_unlocked(self, obj); @@ -540,14 +644,14 @@ return result; } -static int aml__obj_try_add(struct aml* self, void* obj) +static int aml__obj_try_add(struct aml* self, struct aml_obj* obj) { int rc = -1; pthread_mutex_lock(&self->obj_list_mutex); if (!aml__obj_is_started_unlocked(self, obj)) { - aml_ref(obj); + aml_obj_ref(obj); LIST_INSERT_HEAD(&self->obj_list, (struct aml_obj*)obj, link); rc = 0; } @@ -560,7 +664,7 @@ static void aml__obj_remove_unlocked(struct aml* self, void* obj) { LIST_REMOVE((struct aml_obj*)obj, link); - aml_unref(obj); + aml_obj_unref(obj); } static void aml__obj_remove(struct aml* self, void* obj) @@ -654,8 +758,7 @@ return -1; } -EXPORT -int aml_start(struct aml* self, void* obj) +static int aml_start_obj(struct aml* self, struct aml_obj* obj) { if (aml__obj_try_add(self, obj) < 0) return -1; @@ -720,19 +823,41 @@ return -1; } -EXPORT -int aml_stop(struct aml* self, void* obj) +static int aml_stop_obj(struct aml* self, struct aml_obj* obj) { - aml_ref(obj); + aml_obj_ref(obj); if (aml__obj_try_remove(self, obj) >= 0) aml__stop_unchecked(self, obj); - aml_unref(obj); + aml_obj_unref(obj); return 0; } +#define X(type) \ +EXPORT int aml_start_ ## type(struct aml* aml, struct aml_ ## type* obj) \ +{ \ + return aml_start_obj(aml, &obj->obj); \ +} \ +EXPORT int aml_stop_ ## type(struct aml* aml, struct aml_ ## type* obj) \ +{ \ + return aml_stop_obj(aml, &obj->obj); \ +} \ +EXPORT bool aml_is_ ## type ## _started(struct aml* aml, struct aml_ ## type* obj) \ +{ \ + return aml_is_obj_started(aml, &obj->obj); \ +} + +X(handler) +X(timer) +X(ticker) +X(signal) +X(work) +X(idle) + +#undef X + static struct aml_timer* aml__get_timer_with_earliest_deadline(struct aml* self) { uint64_t deadline = UINT64_MAX; @@ -789,16 +914,17 @@ /* A reference is kept here in case an object is stopped inside the * callback. We want the object to live until we're done with it. */ - aml_ref(obj); + aml_obj_ref(obj); - if (obj->cb && aml_is_started(self, obj)) { + if (aml_is_obj_started(self, obj)) { /* Single-shot objects must be stopped before the callback so * that they can be restarted from within the callback. */ if (aml__obj_is_single_shot(obj)) - aml_stop(self, obj); + aml_stop_obj(self, obj); - obj->cb(obj); + if (obj->cb) + obj->cb(obj); } if (obj->type == AML_OBJ_HANDLER) { @@ -809,7 +935,7 @@ aml__mod_fd(self, handler); } - aml_unref(obj); + aml_obj_unref(obj); } /* Might exit earlier than timeout. It's up to the user to check */ @@ -851,7 +977,7 @@ struct aml_obj* obj; while ((obj = aml__event_dequeue(self)) != NULL) { aml__handle_event(self, obj); - aml_unref(obj); + aml_obj_unref(obj); } pthread_sigmask(SIG_SETMASK, &sig_old, NULL); @@ -882,19 +1008,6 @@ self->backend.exit(self->state); } -EXPORT -int aml_ref(void* obj) -{ - struct aml_obj* self = obj; - - aml__ref_lock(); - assert(self->ref >= 0); - int ref = self->ref++; - aml__ref_unlock(); - - return ref; -} - static void aml__free(struct aml* self) { while (!LIST_EMPTY(&self->obj_list)) { @@ -912,7 +1025,7 @@ while (!TAILQ_EMPTY(&self->event_queue)) { struct aml_obj* obj = TAILQ_FIRST(&self->event_queue); TAILQ_REMOVE(&self->event_queue, obj, event_link); - aml_unref(obj); + aml_obj_unref(obj); } pthread_mutex_destroy(&self->timer_list_mutex); @@ -922,112 +1035,6 @@ free(self); } -static void aml__free_handler(struct aml_handler* self) -{ - if (self->obj.free_fn) - self->obj.free_fn(self->obj.userdata); - - free(self); -} - -static void aml__free_timer(struct aml_timer* self) -{ - if (self->obj.free_fn) - self->obj.free_fn(self->obj.userdata); - - free(self); -} - -static void aml__free_signal(struct aml_signal* self) -{ - if (self->obj.free_fn) - self->obj.free_fn(self->obj.userdata); - - free(self); -} - -static void aml__free_work(struct aml_work* self) -{ - if (self->obj.free_fn) - self->obj.free_fn(self->obj.userdata); - - free(self); -} - -static void aml__free_idle(struct aml_idle* self) -{ - if (self->obj.free_fn) - self->obj.free_fn(self->obj.userdata); - - free(self); -} - -EXPORT -int aml_unref(void* obj) -{ - struct aml_obj* self = obj; - - aml__ref_lock(); - int ref = --self->ref; - aml__ref_unlock(); - - assert(ref >= 0); - if (ref > 0) - goto done; - - aml__ref_lock(); - while (!LIST_EMPTY(&self->weak_refs)) { - struct aml_weak_ref* ref = LIST_FIRST(&self->weak_refs); - ref->obj = NULL; - LIST_REMOVE(ref, link); - } - aml__ref_unlock(); - - switch (self->type) { - case AML_OBJ_AML: - aml__free(obj); - break; - case AML_OBJ_HANDLER: - aml__free_handler(obj); - break; - case AML_OBJ_TIMER: - /* fallthrough */ - case AML_OBJ_TICKER: - aml__free_timer(obj); - break; - case AML_OBJ_SIGNAL: - aml__free_signal(obj); - break; - case AML_OBJ_WORK: - aml__free_work(obj); - break; - case AML_OBJ_IDLE: - aml__free_idle(obj); - break; - default: - abort(); - break; - } - -done: - return ref; -} - -EXPORT -void* aml_get_userdata(const void* obj) -{ - const struct aml_obj* aml_obj = obj; - return aml_obj->userdata; -} - -EXPORT -void aml_set_userdata(void* obj, void* userdata, aml_free_fn free_fn) -{ - struct aml_obj* aml_obj = obj; - aml_obj->userdata = userdata; - aml_obj->free_fn = free_fn; -} - void aml_emit(struct aml* self, void* ptr, uint32_t revents) { struct aml_obj* obj = ptr; @@ -1046,7 +1053,7 @@ pthread_mutex_lock(&self->event_queue_mutex); if (obj->n_events++ == 0) TAILQ_INSERT_TAIL(&self->event_queue, obj, event_link); - aml_ref(obj); + aml_obj_ref(obj); pthread_mutex_unlock(&self->event_queue_mutex); pthread_sigmask(SIG_SETMASK, &sig_old, NULL); } @@ -1073,22 +1080,16 @@ } EXPORT -int aml_get_fd(const void* ptr) +int aml_loop_get_fd(const struct aml* self) { - const struct aml_obj* obj = ptr; - - switch (obj->type) { - case AML_OBJ_AML:; - const struct aml* aml = ptr; - return aml->backend.get_fd ? - aml->backend.get_fd(aml->state) : -1; - case AML_OBJ_HANDLER: - return ((struct aml_handler*)ptr)->fd; - default: - break; - } + return self->backend.get_fd ? + self->backend.get_fd(self->state) : -1; +} - return -1; +EXPORT +int aml_handler_get_fd(const struct aml_handler* self) +{ + return self->fd; } EXPORT @@ -1120,18 +1121,13 @@ } EXPORT -void aml_set_duration(void* ptr, uint64_t duration) +void aml_timer_set_duration(struct aml_timer* self, uint64_t duration) { - struct aml_obj* obj = ptr; - - switch (obj->type) { - case AML_OBJ_TIMER: /* fallthrough */ - case AML_OBJ_TICKER: - ((struct aml_timer*)ptr)->timeout = duration; - return; - default: - break; - } + self->timeout = duration; +} - abort(); +EXPORT +void aml_ticker_set_duration(struct aml_ticker* self, uint64_t duration) +{ + self->timeout = duration; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aml-0.3.0/src/epoll.c new/aml-1.0.0/src/epoll.c --- old/aml-0.3.0/src/epoll.c 2023-01-22 13:57:53.000000000 +0100 +++ new/aml-1.0.0/src/epoll.c 2025-07-27 14:59:38.000000000 +0200 @@ -172,9 +172,8 @@ free(sig); } -static void epoll_on_signal(void* obj) +static void epoll_on_signal(struct aml_handler* handler) { - struct aml_handler* handler = obj; struct epoll_signal* ctx = aml_get_userdata(handler); struct signalfd_siginfo fdsi; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aml-0.3.0/src/kqueue.c new/aml-1.0.0/src/kqueue.c --- old/aml-0.3.0/src/kqueue.c 2023-01-22 13:57:53.000000000 +0100 +++ new/aml-1.0.0/src/kqueue.c 2025-07-27 14:59:38.000000000 +0200 @@ -93,7 +93,7 @@ struct kevent events[16]; size_t max_events = sizeof(events) / sizeof(events[0]); - int nfds = kevent(self->fd, NULL, 0, events, max_events, &ts); + int nfds = kevent(self->fd, NULL, 0, events, max_events, timeout >= 0 ? &ts : NULL); for (int i = 0; i < nfds; ++i) kq_emit_event(self, &events[i]); @@ -180,8 +180,17 @@ struct kq_state* self = state; struct kevent event; +#ifdef __MACH__ + struct timespec ts = { 0 }; + clock_gettime(CLOCK_REALTIME, &ts); + uint64_t current_time = ts.tv_sec * UINT64_C(1000000) + ts.tv_nsec / UINT64_C(1000); + uint64_t relative_deadline = deadline > current_time ? deadline - current_time : 0; + EV_SET(&event, 0, EVFILT_TIMER, EV_ADD | EV_ONESHOT, + NOTE_USECONDS, relative_deadline, NULL); +#else EV_SET(&event, 0, EVFILT_TIMER, EV_ADD | EV_ONESHOT, NOTE_USECONDS | NOTE_ABSTIME, deadline, NULL); +#endif return kevent(self->fd, &event, 1, NULL, 0, NULL); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aml-0.3.0/src/thread-pool.c new/aml-1.0.0/src/thread-pool.c --- old/aml-0.3.0/src/thread-pool.c 2023-01-22 13:57:53.000000000 +0100 +++ new/aml-1.0.0/src/thread-pool.c 2025-07-27 14:59:38.000000000 +0200 @@ -96,8 +96,9 @@ sigfillset(&ss); sigdelset(&ss, SIGCHLD); pthread_sigmask(SIG_BLOCK, &ss, NULL); - +#ifndef __ANDROID__ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); +#endif while (1) { struct default_work* work = dequeue_work();
