Mercurial > vim
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 |