Добрый день,
Как портабельно заснуть на наносекунды? Пытался написать CFFI обертку над nanosleep(), но выяснилось, что __time_t тип зависит от платформы. Tак и придется писать для каждой?
usleep(ns / 1000);
это понятно :)
но на винде usleep()'a нет
Ой, есть же ещё винда. Я последнее время начал об этом забывать ;)
не проверял, но, по-моему, оверхед на вызов нативной функции всяко превысит желаемый интервал в наносекундах
Несомненно. Спать имеет смысл где-то от десятков-сотни us.
> Несомненно. Спать имеет смысл где-то от десятков-сотни us.
это да, хотелось спать в микросекундах, но так как usleep() не везде доступен, a
nanosleep() не везде одинаков, поэтому возник этот вопрос :)
Могу ошибаться, но
(defun usleep (seconds micro-seconds)
(declare (type (unsigned-byte 32) seconds)
(type (integer 0 1000000) micro-seconds))
(sleep (+ seconds (/ micro-seconds 1000000))))(define-compiler-macro usleep (seconds micro-seconds)
(if (zerop seconds)
`(sleep (/ ,micro-seconds 1000000))
`(usleep ,seconds ,micro-seconds)))(defun nanosleep (seconds nano-seconds)
(declare (type (unsigned-byte 32) seconds)
(type (integer 0 1000000000) nano-seconds))
(sleep (+ seconds (/ nano-seconds 1000000000))))(define-compiler-macro nanosleep (seconds nano-seconds)
(if (zerop seconds)
`(sleep (/ ,nano-seconds 1000000000))
`(nano-sleep ,seconds ,nano-seconds)))Нужно смотреть для конкретной реализации - какое разрешение у sleеp, но по стандарту она принимает real, так что какое-то разрешение есть.
Ещё sb-unix:nanosleep - для SBCL не на винде.
Ещё
(defpackage #:nanosleep
(:use #:common-lisp
#:cffi)
(:export #:nanosleep))(in-package #:nanosleep)#+win32
(progn
(define-foreign-library cygwin1
(t (:default "cygwin1")))
(use-foreign-library cygwin1))(defctype time-t
#-(or openbsd netbsd) :long
#+(or openbsd netbsd) :int)(defcstruct timespec
(tv-sec time-t)
(tv-nsec :long))(declaim (inline %nanosleep))
(defcfun ("nanosleep" %nanosleep) :int
(interval :pointer)
(remainder :pointer))(defun nanosleep (seconds nano-seconds)
(declare (type (unsigned-byte 32) seconds)
(type (integer 0 1000000000) nano-seconds))
(with-foreign-objects ((interval 'timespec)
(remainder 'timespec))
(setf (foreign-slot-value interval 'timespec 'tv-sec) seconds
(foreign-slot-value interval 'timespec 'tv-nsec) nano-seconds)
(%nanosleep interval remainder)))Работает на Linux (и наверно на других юниксах) но не работает на win32 - видимо тягать cygwin1.dll всё таки не так надёжно :)
И sb-win32:millisleep на винде, в итоге sleep просто готовит аргументы из real и вызывает sb-unix:nanosleep или sb-win32:millisleep в зависимости от платформы.
А ещё (будет самое лучшее разрешение) можно засыпать на n-ое количество nop-ов
(sb-c:defknown %%nop () t)(sb-c:define-vop (%%nop)
(:translate %%nop)
(:policy :fast-safe)
(:generator 0 (sb-c::inst nop)))(declaim (inline %nop))
(defun %nop () (%%nop))(defmacro nop (count)
`(progn
,@(loop :repeat count
:collect '(%nop))))CL-USER>
(macroexpand '(nop 5))
(PROGN (%NOP) (%NOP) (%NOP) (%NOP) (%NOP))(defun foo ()
(nop 5))(disassemble 'foo); disassembly for FOO
; no-arg-parsing entry point
Хотя нет, от этого образ будет разбухать :)
> Работает на Linux (и наверно на других юниксах) но не работает на win32 - видимо тягать cygwin1.dll всё таки не так надёжно :)
не работает на винде, потому что time_t другой размерности :) - 64 бита, и nanosleep() нативный тоже есть
так и придется оборачивать с учетом платформы
А обычный sleep с дробным аргументом не подойдёт? (nanosleep на юниксах и millisleep на винде)
нужны микросекунды. Потом, не понятно, с какой точностью CL'льный sleep работает на других реализациях
А еще можно на нное кол-во факториалов засыпать :)
Ага, "как заснуть с помощью холостого цикла" :) Как я слышал nop-ами спят в разных там сопрограммах в микроконтроллерах (явно не наш случай).
Тот или иной *sleep хотя бы даёт что-то понять ядру.
А не получится добавить там в defctype size-t #+win32 случай? Чему он там равен. Вообще на видне вроде тольо millisleep, в какой дин. библиотеки может (и есть ли вообще) лежать nanosleep - не известно. В cygwin1.dll есть, но что-то не работает (просто не возвращает управления после вызова).
> Потом, не понятно, с какой точностью CL'льный sleep работает на других реализациях
Я думаю что везде так - nanosleep на юниксах и millisleep на винде, потому что никого другого способа его реализации в голову не приходит (не игнорировать же дробные аргументы меньшие единицы).
Прогнал я с nanosleep'ом под винду, пошукал MSDN, его там нет :/
Короче, гугл говорит, что люди говорят, что в винде нет ничего лучше millisleep в user-mode ;)
Ещё одна попытка:
(defpackage #:sleep
(:use #:common-lisp
#:cffi)
(:export #:usleep
#:nanosleep
#:millisleep))(in-package #:sleep);;;; using `cygwin1.dll' on win32 platform
#+win32
(progn
(define-foreign-library cygwin1
(t (:default "cygwin1")))
(use-foreign-library cygwin1));;; From the `usleep' man page:
(defctype portable-useconds-t :unsigned-int)(defctype time-t
#-(or openbsd netbsd) :long #+(or openbsd netbsd) :int)(defcstruct timespec
(tv-sec time-t)
(tv-nsec :long))
(declaim (inline %usleep))
(defcfun ("usleep" %usleep) :void
(usec portable-useconds-t))(declaim (inline %nanosleep))
(defcfun ("nanosleep" %nanosleep) :int
(interval :pointer)
(remainder :pointer))#+win32
(progn
(declaim (inline %millisleep))
(defcfun ("Sleep@4" %millisleep) :void
(milliseconds :unsigned-short)))
(defun usleep (useconds)
(declare (type (integer 0 1000000) useconds))
(%usleep useconds)
(values))(defun nanosleep (seconds nano-seconds)
(declare (type (unsigned-byte 32) seconds)
(type (integer 0 1000000000) nano-seconds))
(with-foreign-objects ((interval 'timespec)
(remainder 'timespec))
(setf (foreign-slot-value interval 'timespec 'tv-sec) seconds
(foreign-slot-value interval 'timespec 'tv-nsec) nano-seconds)
(%nanosleep interval remainder)))(defun millisleep (milliseconds)
(declare (type (integer 0 1000) milliseconds))
#-win32
(%usleep (* milliseconds 1000))
#+win32
(%millisleep milliseconds)
(values))В итоге на винде работает только родной millisleep (который sleep в winapi), а цыгвин рушит sbcl:
(load "sleep.lisp")(sleep:millisleep 1)
(sleep:usleep 1)
fatal error encountered in SBCL pid 1304
(tid 0x002C1558):
gc signals blocked
Welcome to LDB, a low-level debugger for the Lisp runtime environment.
ldb>
(load "sleep.lisp")(sleep:nanosleep 0 1)
fatal error encountered in SBCL pid 1536
(tid 0x003D1558):
gc signals blocked
Welcome to LDB, a low-level debugger for the Lisp runtime environment.
ldb>
У них (в cygwin) в рассылке писалось что usleep вызывает nanosleep, а nanosleep лежит в sygnal.c - вот видимо он сигналами что-то там и рушит (хотя какие сигналы на винде?).
У них (в cygwin) в рассылке писалось что usleep вызывает nanosleep, а nanosleep лежит в sgnal.c - вот видимо он сигналами что-то там и рушит (хотя какие сигналы на винде?).