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.
精彩评论