On Thu, 24 Sep 2026 16:40:34 +0200,
Stuart Henderson <[email protected]> wrote:
> 
> On 2026/09/23 18:49, Brad Smith wrote:
> > On Tue, Sep 22, 2026 at 09:17:19PM +0100, Stuart Henderson wrote:
> > > On 2026/09/22 21:04, Kirill A. Korinsky wrote:
> > > > Well, check-shlib-syms states that here no difference... probably
> > > > SHARED_LIBS really doesn't need a bump.
> > > 
> > > it seemed that way to me (and I was quite happy to get rid of all those
> > > patches!).
> > > 
> > > > Anyway, here a diff which a bit hacky and fixes regression in tdesktop 
> > > > and
> > > > 64gram, and I think in other similar places.
> > > 
> > > > Thoughts?
> > > 
> > > thanks, that makes sense. ok.
> > 
> > This looks like a more appropraite fix.
> > 
> > 
> > Index: Makefile
> > ===================================================================
> > RCS file: /cvs/ports/devel/libdispatch/Makefile,v
> > retrieving revision 1.13
> > diff -u -p -u -p -r1.13 Makefile
> > --- Makefile        22 Sep 2026 20:26:42 -0000      1.13
> > +++ Makefile        23 Sep 2026 22:24:43 -0000
> > @@ -2,7 +2,7 @@ COMMENT =   support for concurrent code ex
> >  
> >  PKGNAME =  libdispatch-$V
> >  V =                6.4.0
> > -REVISION = 0
> > +REVISION = 1
> >  
> >  GH_ACCOUNT =       apple
> >  GH_PROJECT =       swift-corelibs-libdispatch
> > Index: patches/patch-src_event_event_config_h
> > ===================================================================
> > RCS file: patches/patch-src_event_event_config_h
> > diff -N patches/patch-src_event_event_config_h
> > --- patches/patch-src_event_event_config_h  22 Sep 2026 20:26:42 -0000      
> > 1.1
> > +++ /dev/null       1 Jan 1970 00:00:00 -0000
> > @@ -1,18 +0,0 @@
> > -https://github.com/swiftlang/swift-corelibs-libdispatch/pull/960
> > -
> > -Index: src/event/event_config.h
> > ---- src/event/event_config.h.orig
> > -+++ src/event/event_config.h
> > -@@ -116,9 +116,10 @@
> > - # define NOTE_FUNLOCK 0x00000100
> > - # endif
> > - 
> > --// FreeBSD's kevent does not support those
> > -+// FreeBSD's and OpenBSD's kevent does not support those
> > -+// OpenBSD's NOTE_ABSTIME uses CLOCK_REALTIME
> > - # ifndef NOTE_ABSOLUTE
> > --#         ifdef NOTE_ABSTIME
> > -+#         if defined(NOTE_ABSTIME) && !defined(__OpenBSD__)
> > - #                 define NOTE_ABSOLUTE NOTE_ABSTIME
> > - #         else
> > - #                 define NOTE_ABSOLUTE 0
> > Index: patches/patch-src_event_event_kevent_c
> > ===================================================================
> > RCS file: patches/patch-src_event_event_kevent_c
> > diff -N patches/patch-src_event_event_kevent_c
> > --- /dev/null       1 Jan 1970 00:00:00 -0000
> > +++ patches/patch-src_event_event_kevent_c  23 Sep 2026 22:24:43 -0000
> > @@ -0,0 +1,41 @@
> > +- Use relative kqueue deadlines for BSD uptime and monotonic timers
> > +  https://github.com/swiftlang/swift-corelibs-libdispatch/pull/943
> > +
> > +Index: src/event/event_kevent.c
> > +--- src/event/event_kevent.c.orig
> > ++++ src/event/event_kevent.c
> > +@@ -60,10 +60,22 @@ DISPATCH_STATIC_GLOBAL(struct dispatch_muxnote_bucket_
> > + #define DISPATCH_NOTE_CLOCK_UPTIME    0
> > + #endif
> > + 
> > ++#if defined(__FreeBSD__) || defined(__OpenBSD__)
> > ++// BSD NOTE_ABSTIME deadlines use CLOCK_REALTIME.
> > ++#define DISPATCH_NOTE_ABSOLUTE_WALL      NOTE_ABSOLUTE
> > ++#define DISPATCH_NOTE_ABSOLUTE_MONOTONIC 0
> > ++#define DISPATCH_NOTE_ABSOLUTE_UPTIME    0
> > ++#else
> > ++#define DISPATCH_NOTE_ABSOLUTE_WALL      NOTE_ABSOLUTE
> > ++#define DISPATCH_NOTE_ABSOLUTE_MONOTONIC NOTE_ABSOLUTE
> > ++#define DISPATCH_NOTE_ABSOLUTE_UPTIME    NOTE_ABSOLUTE
> > ++#endif
> > ++
> > + static const uint32_t _dispatch_timer_index_to_fflags[] = {
> > + #define DISPATCH_TIMER_FFLAGS_INIT(kind, qos, note) \
> > +   [DISPATCH_TIMER_INDEX(DISPATCH_CLOCK_##kind, DISPATCH_TIMER_QOS_##qos)] 
> > = \
> > +-                  DISPATCH_NOTE_CLOCK_##kind | NOTE_ABSOLUTE | 
> > NOTE_LEEWAY | (note)
> > ++  DISPATCH_NOTE_CLOCK_##kind | DISPATCH_NOTE_ABSOLUTE_##kind | \
> > ++  NOTE_LEEWAY | (note)
> > +   DISPATCH_TIMER_FFLAGS_INIT(WALL, NORMAL, 0),
> > +   DISPATCH_TIMER_FFLAGS_INIT(UPTIME, NORMAL, 0),
> > +   DISPATCH_TIMER_FFLAGS_INIT(MONOTONIC, NORMAL, 0),
> > +@@ -2406,6 +2418,10 @@ 
> > _dispatch_event_loop_timer_arm(dispatch_timer_heap_t d
> > +   }
> > + #if !NOTE_ABSOLUTE
> > +   target = range.delay;
> > ++#elif defined(__FreeBSD__) || defined(__OpenBSD__)
> > ++  if (clock != DISPATCH_CLOCK_WALL) {
> > ++          target -= _dispatch_time_now_cached(clock, nows);
> > ++  }
> > + #endif
> > + 
> > +   _dispatch_event_loop_timer_program(dth, tidx, target, range.leeway,
> > Index: patches/patch-tests_CMakeLists_txt
> > ===================================================================
> > RCS file: patches/patch-tests_CMakeLists_txt
> > diff -N patches/patch-tests_CMakeLists_txt
> > --- /dev/null       1 Jan 1970 00:00:00 -0000
> > +++ patches/patch-tests_CMakeLists_txt      23 Sep 2026 22:24:43 -0000
> > @@ -0,0 +1,17 @@
> > +- Use relative kqueue deadlines for BSD uptime and monotonic timers
> > +  https://github.com/swiftlang/swift-corelibs-libdispatch/pull/943
> > +
> > +Index: tests/CMakeLists.txt
> > +--- tests/CMakeLists.txt.orig
> > ++++ tests/CMakeLists.txt
> > +@@ -140,6 +140,10 @@ set(DISPATCH_C_TESTS
> > +     io_pipe_close
> > +     select)
> > + 
> > ++if(UNIX)
> > ++  list(APPEND DISPATCH_C_TESTS timer_idle)
> > ++endif()
> > ++
> > + # Tests that usually pass, but occasionally fail.
> > + # Excluded by default for purposes of Swift CI
> > + if(EXTENDED_TEST_SUITE)
> > Index: patches/patch-tests_dispatch_timer_idle_c
> > ===================================================================
> > RCS file: patches/patch-tests_dispatch_timer_idle_c
> > diff -N patches/patch-tests_dispatch_timer_idle_c
> > --- /dev/null       1 Jan 1970 00:00:00 -0000
> > +++ patches/patch-tests_dispatch_timer_idle_c       23 Sep 2026 22:24:43 
> > -0000
> > @@ -0,0 +1,157 @@
> > +- Use relative kqueue deadlines for BSD uptime and monotonic timers
> > +  https://github.com/swiftlang/swift-corelibs-libdispatch/pull/943
> > +
> > +Index: tests/dispatch_timer_idle.c
> > +--- tests/dispatch_timer_idle.c.orig
> > ++++ tests/dispatch_timer_idle.c
> > +@@ -0,0 +1,150 @@
> > ++/*
> > ++ * This source file is part of the Swift.org open source project
> > ++ *
> > ++ * Copyright (c) 2026 Apple Inc. and the Swift project authors
> > ++ *
> > ++ * Licensed under Apache License v2.0 with Runtime Library Exception
> > ++ *
> > ++ * See https://swift.org/LICENSE.txt for license information
> > ++ * See https://swift.org/CONTRIBUTORS.txt for the list of Swift project 
> > authors
> > ++ *
> > ++ */
> > ++
> > ++#include <dispatch/dispatch.h>
> > ++
> > ++#include <bsdtests.h>
> > ++#include "dispatch_test.h"
> > ++
> > ++#include <errno.h>
> > ++#include <stdatomic.h>
> > ++#include <stdint.h>
> > ++#include <stdio.h>
> > ++#include <stdlib.h>
> > ++#include <sys/resource.h>
> > ++#include <time.h>
> > ++
> > ++#define OBSERVATION_SECONDS 0.25
> > ++#define MAX_IDLE_CPU_RATIO 0.20
> > ++
> > ++static _Atomic int timer_fired;
> > ++static volatile uint64_t spin_sink;
> > ++
> > ++static void
> > ++monotonic_now(struct timespec *value)
> > ++{
> > ++  if (clock_gettime(CLOCK_MONOTONIC, value) != 0) {
> > ++  perror("clock_gettime");
> > ++          exit(EXIT_FAILURE);
> > ++  }
> > ++}
> > ++
> > ++static double
> > ++seconds_between(struct timespec start, struct timespec end)
> > ++{
> > ++  return (double)(end.tv_sec - start.tv_sec) +
> > ++          (double)(end.tv_nsec - start.tv_nsec) / (double)NSEC_PER_SEC;
> > ++}
> > ++
> > ++static double
> > ++timeval_seconds(struct timeval value)
> > ++{
> > ++  return (double)value.tv_sec +
> > ++          (double)value.tv_usec / (double)USEC_PER_SEC;
> > ++}
> > ++
> > ++static double
> > ++process_cpu_seconds(void)
> > ++{
> > ++  struct rusage usage;
> > ++
> > ++  if (getrusage(RUSAGE_SELF, &usage) != 0) {
> > ++          perror("getrusage");
> > ++          exit(EXIT_FAILURE);
> > ++  }
> > ++  return timeval_seconds(usage.ru_utime) + 
> > timeval_seconds(usage.ru_stime);
> > ++}
> > ++
> > ++static double
> > ++measure_busy_cpu_ratio(void)
> > ++{
> > ++  struct timespec wall_start, wall_now;
> > ++  double cpu_start, cpu_end;
> > ++
> > ++  monotonic_now(&wall_start);
> > ++  cpu_start = process_cpu_seconds();
> > ++  do {
> > ++          spin_sink++;
> > ++          monotonic_now(&wall_now);
> > ++  } while (seconds_between(wall_start, wall_now) < OBSERVATION_SECONDS);
> > ++  cpu_end = process_cpu_seconds();
> > ++
> > ++  return (cpu_end - cpu_start) / seconds_between(wall_start, wall_now);
> > ++}
> > ++
> > ++static void
> > ++unexpected_timer_fire(void *context)
> > ++{
> > ++  (void)context;
> > ++  atomic_store_explicit(&timer_fired, 1, memory_order_relaxed);
> > ++}
> > ++
> > ++static void
> > ++observe_idle_timer(double *wall_seconds, double *cpu_seconds)
> > ++{
> > ++  struct timespec wall_start, wall_end;
> > ++  struct timespec remaining = {
> > ++          .tv_sec = 0,
> > ++          .tv_nsec = (long)(OBSERVATION_SECONDS * (double)NSEC_PER_SEC),
> > ++  };
> > ++  dispatch_source_t timer;
> > ++  double cpu_start;
> > ++  int sleep_result;
> > ++
> > ++  timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,
> > ++                  
> > dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
> > ++  test_ptr_notnull("dispatch_source_create", timer);
> > ++  dispatch_source_set_event_handler_f(timer, unexpected_timer_fire);
> > ++  dispatch_source_set_timer(timer,
> > ++                  dispatch_time(DISPATCH_TIME_NOW, 3600 * NSEC_PER_SEC),
> > ++                  DISPATCH_TIME_FOREVER, 0);
> > ++  dispatch_resume(timer);
> > ++
> > ++  monotonic_now(&wall_start);
> > ++  cpu_start = process_cpu_seconds();
> > ++  do {
> > ++          sleep_result = nanosleep(&remaining, &remaining);
> > ++  } while (sleep_result == -1 && errno == EINTR);
> > ++  if (sleep_result != 0) {
> > ++          perror("nanosleep");
> > ++          exit(EXIT_FAILURE);
> > ++  }
> > ++  *cpu_seconds = process_cpu_seconds() - cpu_start;
> > ++  monotonic_now(&wall_end);
> > ++  *wall_seconds = seconds_between(wall_start, wall_end);
> > ++
> > ++  dispatch_source_cancel(timer);
> > ++  dispatch_release(timer);
> > ++}
> > ++
> > ++int
> > ++main(void)
> > ++{
> > ++  double busy_cpu_ratio, idle_wall_seconds, idle_cpu_seconds;
> > ++  double idle_cpu_ratio, relative_cpu_ratio;
> > ++
> > ++  dispatch_test_start("Dispatch idle timer CPU usage");
> > ++
> > ++  busy_cpu_ratio = measure_busy_cpu_ratio();
> > ++  observe_idle_timer(&idle_wall_seconds, &idle_cpu_seconds);
> > ++  idle_cpu_ratio = idle_cpu_seconds / idle_wall_seconds;
> > ++  relative_cpu_ratio = idle_cpu_ratio / busy_cpu_ratio;
> > ++
> > ++  fprintf(stderr, "idle=%f busy=%f relative=%f\n",
> > ++                  idle_cpu_ratio, busy_cpu_ratio, relative_cpu_ratio);
> > ++  test_long("timer fired", atomic_load_explicit(&timer_fired,
> > ++                  memory_order_relaxed), 0);
> > ++  test_double_less_than("idle timer CPU ratio", relative_cpu_ratio,
> > ++                  MAX_IDLE_CPU_RATIO);
> > ++  test_stop();
> > ++  return 0;
> > ++}
> > 
> 
> asterisk looks ok, cpu use with Telegram is looking reasonably sane
> once it's settled down after startup. Kirill, does it seem ok for you
> too?
> 

Yes, it reads OK and looks better, but I haven't tested it.

Anyway, in case of telegram CPU usage was near instant and easy to catch.

-- 
wbr, Kirill

Reply via email to