comparison src/os_macosx.m @ 29071:b90bca860b5a v8.2.5057

patch 8.2.5057: using gettimeofday() for timeout is very inefficient Commit: https://github.com/vim/vim/commit/6574577cacd393ab7591fc776ea060eebc939e55 Author: Paul Ollis <paul@cleversheep.org> Date: Sun Jun 5 16:55:54 2022 +0100 patch 8.2.5057: using gettimeofday() for timeout is very inefficient Problem: Using gettimeofday() for timeout is very inefficient. Solution: Set a platform dependent timer. (Paul Ollis, closes https://github.com/vim/vim/issues/10505)
author Bram Moolenaar <Bram@vim.org>
date Sun, 05 Jun 2022 18:00:08 +0200
parents c346db463a59
children 24b7e14d55e2
comparison
equal deleted inserted replaced
29070:8bf8001ef6d5 29071:b90bca860b5a
20 #endif 20 #endif
21 21
22 /* Avoid a conflict for the definition of Boolean between Mac header files and 22 /* Avoid a conflict for the definition of Boolean between Mac header files and
23 * X11 header files. */ 23 * X11 header files. */
24 #define NO_X11_INCLUDES 24 #define NO_X11_INCLUDES
25
26 #include <stdbool.h>
27 #include <mach/boolean.h>
28 #include <sys/errno.h>
29 #include <stdlib.h>
30
31 #include <dispatch/dispatch.h>
25 32
26 #include "vim.h" 33 #include "vim.h"
27 #import <AppKit/AppKit.h> 34 #import <AppKit/AppKit.h>
28 35
29 36
206 [pool release]; 213 [pool release];
207 } 214 }
208 215
209 #endif /* FEAT_CLIPBOARD */ 216 #endif /* FEAT_CLIPBOARD */
210 217
218 #ifdef FEAT_RELTIME
219 /*
220 * The following timer code is based on a Gist by Jorgen Lundman:
221 *
222 * https://gist.github.com/lundman
223 */
224
225 typedef struct macos_timer macos_timer_T;
226
227 static void
228 _timer_cancel(void *arg UNUSED)
229 {
230 // This is not currently used, but it might be useful in the future and
231 // it is non-trivial enough to provide as usable implementation.
232 # if 0
233 macos_timer_T *timerid = (macos_timer_T *)arg;
234
235 dispatch_release(timerid->tim_timer);
236 dispatch_release(timerid->tim_queue);
237 timerid->tim_timer = NULL;
238 timerid->tim_queue = NULL;
239 free(timerid);
240 # endif
241 }
242
243 static void
244 _timer_handler(void *arg)
245 {
246 macos_timer_T *timerid = (macos_timer_T *)arg;
247 union sigval sv;
248
249 sv.sival_ptr = timerid->tim_arg;
250
251 if (timerid->tim_func != NULL)
252 timerid->tim_func(sv);
253 }
254
255 static uint64_t
256 itime_to_ns(const struct timespec *it)
257 {
258 time_t sec = it->tv_sec;
259 long nsec = it->tv_nsec;
260 uint64_t ns = NSEC_PER_SEC * sec + nsec;
261
262 return ns == 0 ? DISPATCH_TIME_FOREVER : ns;
263 }
264
265 /*
266 * A partial emulation of the POSIX timer_create function.
267 *
268 * The limitations and differences include:
269 *
270 * - Only CLOCK_REALTIME and CLOCK_MONOTONIC are supported as clockid
271 * values.
272 * - Even if CLOCK_REALTIME is specified, internally the mach_absolute_time
273 * source is used internally.
274 * - The only notification method supported is SIGEV_THREAD.
275 */
276 inline int
277 timer_create(clockid_t clockid, struct sigevent *sevp, timer_t *timerid)
278 {
279 macos_timer_T *timer = NULL;
280
281 // We only support real time and monotonic clocks; and SIGEV_THREAD
282 // notification. In practice, there is no difference between the two
283 // types of clocks on MacOS - we always use the mach_machine_time
284 // source.
285 if ( (clockid != CLOCK_REALTIME && clockid != CLOCK_MONOTONIC)
286 || sevp->sigev_notify != SIGEV_THREAD)
287 {
288 semsg("clockid: %d %d", clockid, CLOCK_REALTIME);
289 semsg("notify: %d %d", sevp->sigev_notify, SIGEV_THREAD);
290 errno = ENOTSUP;
291 return -1;
292 }
293
294 timer = (macos_timer_T *)malloc(sizeof(macos_timer_T));
295 if (timer == NULL)
296 {
297 errno = ENOMEM;
298 return -1;
299 }
300 *timerid = timer;
301
302 timer->tim_queue = dispatch_queue_create(
303 "org.vim.timerqueue", NULL);
304 if (timer->tim_queue == NULL)
305 {
306 errno = ENOMEM;
307 return -1;
308 }
309
310 timer->tim_timer = dispatch_source_create(
311 DISPATCH_SOURCE_TYPE_TIMER, 0, 0, timer->tim_queue);
312 if (timer->tim_timer == NULL)
313 {
314 errno = ENOMEM;
315 return -1;
316 }
317
318 timer->tim_func = sevp->sigev_notify_function;
319 timer->tim_arg = sevp->sigev_value.sival_ptr;
320
321 dispatch_set_context(timer->tim_timer, timer);
322 dispatch_source_set_event_handler_f(timer->tim_timer, _timer_handler);
323 dispatch_source_set_cancel_handler_f(timer->tim_timer, _timer_cancel);
324
325 dispatch_resume(timer->tim_timer);
326
327 return 0;
328 }
329
330 /*
331 * A partial emulation of the POSIX timer_settime function.
332 *
333 * The limitations and differences include:
334 *
335 * - The flags argument is ignored. The supplied new_value is therfore
336 * always treated as a relative time.
337 * - The old_value argument is ignored.
338 */
339 int
340 timer_settime(
341 timer_t timerid,
342 int unused_flags UNUSED,
343 const struct itimerspec *new_value,
344 struct itimerspec *old_value UNUSED)
345 {
346 uint64_t first_shot = itime_to_ns(&new_value->it_value);
347
348 if (timerid == NULL)
349 return 0;
350
351 if (first_shot == DISPATCH_TIME_FOREVER)
352 {
353 dispatch_source_set_timer(
354 timerid->tim_timer, first_shot, first_shot, 0);
355 }
356 else
357 {
358 uint64_t interval = itime_to_ns(&new_value->it_interval);
359
360 dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, first_shot);
361 dispatch_source_set_timer(timerid->tim_timer, start, interval, 0);
362 }
363
364 return 0;
365 }
366
367 /*
368 * An emulation of the POSIX timer_delete function.
369 *
370 * Disabled because it is not currently used, but an implemented provided
371 * for completeness and possible future use.
372 */
373 #if 0
374 int
375 timer_delete(timer_t timerid)
376 {
377 /* Calls _timer_cancel() */
378 if (timerid != NULL)
379 dispatch_source_cancel(timerid->tim_timer);
380
381 return 0;
382 }
383 #endif
384
385 #endif /* FEAT_RELTIME */
386
211 /* Lift the compiler warning suppression. */ 387 /* Lift the compiler warning suppression. */
212 #if defined(__clang__) && defined(__STRICT_ANSI__) 388 #if defined(__clang__) && defined(__STRICT_ANSI__)
213 # pragma clang diagnostic pop 389 # pragma clang diagnostic pop
214 # pragma clang diagnostic pop 390 # pragma clang diagnostic pop
215 #endif 391 #endif