(declare (type unix-pathname path)
(type fixnum flags)
(type unix-file-mode mode))
- (int-syscall ("open" c-string int int)
- path
- (logior #!+win32 o_binary
- #!+largefile o_largefile
- flags)
- mode))
+ (with-restarted-syscall (value errno)
+ (int-syscall ("open" c-string int int)
+ path
+ (logior #!+win32 o_binary
+ #!+largefile o_largefile
+ flags)
+ mode)))
;;; UNIX-CLOSE accepts a file descriptor and attempts to close the file
;;; associated with it.
(rem (struct timespec)))
(setf (slot req 'tv-sec) secs)
(setf (slot req 'tv-nsec) nsecs)
- (loop while (eql sb!unix:eintr
- (nth-value 1
- (int-syscall ("nanosleep" (* (struct timespec))
- (* (struct timespec)))
- (addr req) (addr rem))))
- do (rotatef req rem))))
+ (loop while (and (eql sb!unix:eintr
+ (nth-value 1
+ (int-syscall ("nanosleep" (* (struct timespec))
+ (* (struct timespec)))
+ (addr req) (addr rem))))
+ ;; KLUDGE: On Darwin, if an interrupt cases nanosleep to
+ ;; take longer than the requested time, the call will
+ ;; return with EINT and (unsigned)-1 seconds in the
+ ;; remainder timespec, which would cause us to enter
+ ;; nanosleep again for ~136 years. So, we check that the
+ ;; remainder time is actually decreasing.
+ ;;
+ ;; It would be neat to do this bit of defensive
+ ;; programming on all platforms, but unfortunately on
+ ;; Linux, REM can be a little higher than REQ if the
+ ;; nanosleep() call is interrupted quickly enough,
+ ;; probably due to the request being rounded up to the
+ ;; nearest HZ. This would cause the sleep to return way
+ ;; too early.
+ #!+darwin
+ (let ((rem-sec (slot rem 'tv-sec))
+ (rem-nsec (slot rem 'tv-nsec)))
+ (when (or (> secs rem-sec)
+ (and (= secs rem-sec) (>= nsecs rem-nsec)))
+ (setf secs rem-sec
+ nsecs rem-nsec)
+ t)))
+ do (rotatef req rem))))
(defun unix-get-seconds-west (secs)
(multiple-value-bind (ignore seconds dst) (get-timezone secs)