开发者

select() doesn't wait any changes

I'm not quite sure what i'm doing wrong. I need to get file change event by select() system call. So the problem is that it doesn't wait, and immediately returns TRUE result. It's looks like i didn't change the file position to the end of file, which i did.

Here is the code

(defvar *fd-setsize* 1024)

(defvar *fd-bits-size* (/ *fd-setsize* sb-vm:n-machine-word-bits))

(defcstruct ccx-fd-set
  (fds-bits :long :count #.*fd-bits-size*))

(defun ccx-strerror (errnum)
  "Wrapper for strerror - return string describing error number"
  (foreign-funcall "strerror" :int errnum :string))

(defun ccx-test (function-result &optional (caller nil caller-p))
  "Wrapper for native functuions. It on succecc it will return function-result, but if not,
   it will also report an error from errno."
  (labels ((error-signal ()
         (if caller-p 
         (warn "~a ~a" caller (ccx-strerror *errno*))
         (warn "~a" (ccx-strerror *errno*)))))
    (cond
      ((and (realp function-result)
        (minusp function-result)) (error-signal)))
    function-result))

(defun ccx-select (nfds readfds writefds exceptfds timeout)
  (ccx-test (fore开发者_运维百科ign-funcall "select" :int nfds :pointer readfds :pointer writefds
                 :pointer exceptfds :pointer timeout :int) "ccx-select"))

(defun ccx-pselect (nfds readfds writefds exceptfds timeout sigmask)
  (ccx-test (foreign-funcall "pselect" :int nfds :pointer readfds :pointer writefds
                 :pointer exceptfds :pointer timeout :pointer sigmask :int) "ccx-pselect"))

;; #define __FD_SET(d, set) \
;;   ((void) (__FDS_BITS (set)[__FDELT (d)] |= __FDMASK (d)))
(defmacro fd-set (offset fd-set)
  (with-gensyms (word bit)
    `(with-foreign-slots ((fds-bits) ,fd-set ccx-fd-set)
       (multiple-value-bind (,word ,bit) (floor ,offset *fd-bits-size*)
     (setf (mem-aref fds-bits :long ,word)
           ;; #define  __FDMASK(d) ((__fd_mask) 1 << ((d) % __NFDBITS))
           (logior (the (unsigned-byte #.*fd-bits-size*)
             (ash 1 ,bit))
               ;; #define  __FDELT(d)  ((d) / __NFDBITS)
               (mem-aref fds-bits :long ,word)
               ))))))

;; #define __FD_CLR(d, set) \
;;   ((void) (__FDS_BITS (set)[__FDELT (d)] &= ~__FDMASK (d)))
(defmacro fd-clr (offset fd-set)
  (with-gensyms (word bit)
    `(with-foreign-slots ((fds-bits) ,fd-set ccx-fd-set)
       (multiple-value-bind (,word ,bit) (floor ,offset sb-vm:n-machine-word-bits)
     (setf (mem-aref fds-bits :long ,word)
           (logand (the (unsigned-byte #.*fd-bits-size*)
             (ash 1 ,bit))
               (mem-ref fds-bits :long ,word)))))))

;; #define __FD_ISSET(d, set) \
;;   ((__FDS_BITS (set)[__FDELT (d)] & __FDMASK (d)) != 0)
(defmacro fd-isset (offset fd-set)
  (with-gensyms (word bit)
    `(with-foreign-slots ((fds-bits) ,fd-set ccx-fd-set)
       (multiple-value-bind (,word ,bit) (floor ,offset *fd-bits-size*)
     ;; (logbitp ,bit (mem-aref fds-bits :long ,word))
     (logbitp ,bit (mem-aref fds-bits :long ,word))))))

;; # define __FD_ZERO(set)  \
;;   do {                                 \
;;     unsigned int __i;                           \
;;     fd_set *__arr = (set);                      \
;;              4 * 32 = 128  /  4 
;;     for (__i = 0; __i < sizeof (fd_set) / sizeof (__fd_mask); ++__i)       \
;;       __FDS_BITS (__arr)[__i] = 0;                    \
;;   } while (0)
(defmacro fd-zero (&rest fd-sets)
  `(progn
     ,@(loop for el in fd-sets
      collect `(with-foreign-slots ((fds-bits) ,el ccx-fd-set)
             ,@(loop for index upfrom 0 below *fd-bits-size*
              collect `(setf (mem-aref fds-bits :long ,index) 0))))))


(defmacro fd-set-print (&rest fd-sets)
  `(progn
     ,@(loop for el in fd-sets
      collect `(progn
             (format t "~&~s: " ',el)
             ,@(loop for index upfrom 0 below *fd-bits-size* collect
                    `(format t "~d " (mem-aref (foreign-slot-value ,el 'ccx-fd-set 'fds-bits) :long ,index))
                  finally (format t "~%"))))))

This is my run script

(with-open-file (fd "/tmp/test.txt")
  (with-foreign-objects ((fd-set-r 'ccx-fd-set)
             (fd-set-w 'ccx-fd-set)
             (fd-set-x 'ccx-fd-set)
             (timeout 'ccx-timespec))

    (file-position fd (file-length fd))

    (setf (foreign-slot-value timeout 'ccx-timespec 'ccx-tv-sec)  10)
    (setf (foreign-slot-value timeout 'ccx-timespec 'ccx-tv-nsec)  0)

    ;; PRINTING && FLUSHING && PRINTING
    (fd-set-print  fd-set-r fd-set-w fd-set-x)
    (fd-zero fd-set-r fd-set-w fd-set-x)
    (fd-set-print  fd-set-r fd-set-w fd-set-x)

    (fd-set (sb-sys:fd-stream-fd fd) fd-set-r)
    (fd-set (sb-sys:fd-stream-fd fd) fd-set-w)
    (fd-set (sb-sys:fd-stream-fd fd) fd-set-x)
    (fd-set-print  fd-set-r fd-set-w fd-set-x)

    (let ((res (ccx-select *fd-setsize* fd-set-r fd-set-w (null-pointer) timeout)))
      (if (< res 0)
      (format t "~& select () error")
      (loop for index upfrom 0 below *fd-setsize* do
           (progn
         (when (fd-isset index fd-set-r)
           (format t "~& fd ~d read" index))
         (when (fd-isset index fd-set-w)
           (format t "~& fd ~d write" index))
         ;; (when (fd-isset index fd-set-x)
         ;;   (format t "~& fd ~d ex" index))
         ))))))

So here is my C example which doesn't work for me too.

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <fcntl.h>
#include <stdio.h>

int main ()
{
  FILE * pFile;
  long size;

  pFile = fopen ("/tmp/test.txt","rb");
  if (pFile==NULL) perror ("Error opening file");
  else
    {
      while (1){
    fseek (pFile, 0, SEEK_END);
    size=ftell (pFile);
    printf ("Size of myfile.txt: %ld bytes.\n",size);

    fd_set fds;
    struct timeval tv;


    int fd = fileno(pFile);
    FD_ZERO(&fds);
    FD_SET(fd,&fds);
    tv.tv_sec = 2;
    tv.tv_usec = 0;
    int rc = select(fd+1, &fds, NULL, NULL, &tv);

    if (rc < 0) {
      printf("failed\n");
      /* continue; */
    } else if (rc > 0 && FD_ISSET(fd,&fds)) {
      printf("read\n");
    } else  {
      printf("timeout\n");
      /* continue; */
    }

      }
      fclose (pFile);
    }
  return 0;
}

The result of this program is:

Size of test.txt: 2267 bytes.
read
Size of test.txt: 2267 bytes.
read

What's wrong with my code?


You are not doing anything wrong

select()/poll() and similar does not "work" for regular files.

"File descriptors associated with regular files always select true for ready to read, ready to write, and error conditions." - from here

If you want to monitor files for changes, you can use gamin, or operating system dependant APIs, such as inotify on linux, kqueue on BSDs.


Plain (disk) files are always ready for reading; select() is only really useful on devices such as tty's and sockets.

POSIX says:

A descriptor shall be considered ready for reading when a call to an input function with O_NONBLOCK clear would not block, whether or not the function would transfer data successfully. (The function might return data, an end-of-file indication, or an error other than one indicating that it is blocked, and in each of these cases the descriptor shall be considered ready for reading.)

A descriptor shall be considered ready for writing when a call to an output function with O_NONBLOCK clear would not block, whether or not the function would transfer data successfully.

Plus the apposite quote also in the answer by nos:

File descriptors associated with regular files shall always select true for ready to read, ready to write, and error conditions.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜