Commits

Denis Bilenko committed 08d85e6

add 'stat' watchers

Comments (0)

Files changed (4)

gevent/callbacks.h

     static void gevent_callback_##WATCHER_LC(struct ev_loop *, void *, int);
 
 
-#define DEFINE_CALLBACKS               \
+#define DEFINE_CALLBACKS0              \
     DEFINE_CALLBACK(io, IO);           \
     DEFINE_CALLBACK(timer, Timer);     \
     DEFINE_CALLBACK(signal, Signal);   \
     DEFINE_CALLBACK(prepare, Prepare); \
     DEFINE_CALLBACK(fork, Fork);       \
     DEFINE_CALLBACK(async, Async);     \
-    DEFINE_CALLBACK(child, Child);
+    DEFINE_CALLBACK(stat, Stat);
+
+
+#if EV_CHILD_ENABLE
+
+#define DEFINE_CALLBACKS               \
+    DEFINE_CALLBACKS0                  \
+    DEFINE_CALLBACK(child, Child)
+
+#else
+
+#define DEFINE_CALLBACKS DEFINE_CALLBACKS0
+
+#endif
 
 
 DEFINE_CALLBACKS
     void gevent_callback_fork(libev.ev_loop, void*, int)
     void gevent_callback_async(libev.ev_loop, void*, int)
     void gevent_callback_child(libev.ev_loop, void*, int)
+    void gevent_callback_stat(libev.ev_loop, void*, int)
     void gevent_signal_check(libev.ev_loop, void*, int)
     void gevent_periodic_signal_check(libev.ev_loop, void*, int)
 
     int FIONREAD
     int errno
 
+cdef extern from "stathelper.c":
+    object _pystat_fromstructstat(void*)
+
 
 UNDEF = libev.EV_UNDEF
 NONE = libev.EV_NONE
 
 #endif
 
+    def stat(self, bytes path, float interval=0.0, ref=True):
+        return stat(self, path, interval, ref)
+
     def callback(self):
         return callback(self)
 
 #endif
 
 
+cdef public class stat(watcher) [object PyGeventStatObject, type PyGeventStat_Type]:
+
+    WATCHER(stat)
+    cdef readonly bytes path
+
+    def __init__(self, loop loop, bytes path, float interval=0.0, ref=True):
+        self.path = path
+        libev.ev_stat_init(&self._watcher, <void *>gevent_callback_stat, <char*>self.path, interval)
+        self.loop = loop
+        if ref:
+            self._flags = 0
+        else:
+            self._flags = 4
+
+    property attr:
+
+        def __get__(self):
+            if not self._watcher.attr.st_nlink:
+                return
+            return _pystat_fromstructstat(&self._watcher.attr)
+
+    property prev:
+
+       def __get__(self):
+            if not self._watcher.prev.st_nlink:
+                return
+            return _pystat_fromstructstat(&self._watcher.prev)
+
+    property interval:
+
+        def __get__(self):
+            return self._watcher.interval
+
+
 cdef public class callback(watcher) [object PyGeventCallbackObject, type PyGeventCallback_Type]:
     """Pseudo-watcher used to execute a callback in the loop as soon as possible."""
 
         int rpid
         int rstatus
 
+    struct stat:
+        int st_nlink
+
+    struct ev_stat:
+        stat attr
+        stat prev
+        double interval
+
     int ev_version_major()
     int ev_version_minor()
 
     void ev_child_start(ev_loop*, ev_child*)
     void ev_child_stop(ev_loop*, ev_child*)
 
+    void ev_stat_init(ev_stat*, void* callback, char*, double)
+    void ev_stat_start(ev_loop*, ev_stat*)
+    void ev_stat_stop(ev_loop*, ev_stat*)
+
     ev_loop* ev_default_loop(unsigned int flags)
     ev_loop* ev_loop_new(unsigned int flags)
     void ev_loop_destroy(ev_loop*)

gevent/stathelper.c

+/* copied from Python-2.7.2/Modules/posixmodule.c */
+#include "structseq.h"
+
+#define STRUCT_STAT struct stat
+
+#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
+#define ST_BLKSIZE_IDX 13
+#else
+#define ST_BLKSIZE_IDX 12
+#endif
+
+#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
+#define ST_BLOCKS_IDX (ST_BLKSIZE_IDX+1)
+#else
+#define ST_BLOCKS_IDX ST_BLKSIZE_IDX
+#endif
+
+#ifdef HAVE_STRUCT_STAT_ST_RDEV
+#define ST_RDEV_IDX (ST_BLOCKS_IDX+1)
+#else
+#define ST_RDEV_IDX ST_BLOCKS_IDX
+#endif
+
+#ifdef HAVE_STRUCT_STAT_ST_FLAGS
+#define ST_FLAGS_IDX (ST_RDEV_IDX+1)
+#else
+#define ST_FLAGS_IDX ST_RDEV_IDX
+#endif
+
+#ifdef HAVE_STRUCT_STAT_ST_GEN
+#define ST_GEN_IDX (ST_FLAGS_IDX+1)
+#else
+#define ST_GEN_IDX ST_FLAGS_IDX
+#endif
+
+#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
+#define ST_BIRTHTIME_IDX (ST_GEN_IDX+1)
+#else
+#define ST_BIRTHTIME_IDX ST_GEN_IDX
+#endif
+
+
+
+static PyObject* posixmodule = NULL;
+static PyTypeObject* pStatResultType = NULL;
+
+
+static PyObject* import_posixmodule(void)
+{
+    if (!posixmodule) {
+        posixmodule = PyImport_ImportModule("posix");
+    }
+    return posixmodule;
+}
+
+
+static PyObject* import_StatResultType(void)
+{
+    PyObject* p = NULL;
+    if (!pStatResultType) {
+        PyObject* module;
+        module = import_posixmodule();
+        if (module) {
+            p = PyObject_GetAttrString(module, "stat_result");
+        }
+    }
+    return p;
+}
+
+static void
+fill_time(PyObject *v, int index, time_t sec, unsigned long nsec)
+{
+    PyObject *fval,*ival;
+#if SIZEOF_TIME_T > SIZEOF_LONG
+    ival = PyLong_FromLongLong((PY_LONG_LONG)sec);
+#else
+    ival = PyInt_FromLong((long)sec);
+#endif
+    if (!ival)
+        return;
+    fval = PyFloat_FromDouble(sec + 1e-9*nsec);
+    PyStructSequence_SET_ITEM(v, index, ival);
+    PyStructSequence_SET_ITEM(v, index+3, fval);
+}
+
+/* pack a system stat C structure into the Python stat tuple
+   (used by posix_stat() and posix_fstat()) */
+static PyObject*
+_pystat_fromstructstat(STRUCT_STAT *st)
+{
+    unsigned long ansec, mnsec, cnsec;
+
+    PyTypeObject* StatResultType = (PyTypeObject*)import_StatResultType();
+
+    PyObject *v = PyStructSequence_New(StatResultType);
+    if (v == NULL)
+        return NULL;
+
+    PyStructSequence_SET_ITEM(v, 0, PyInt_FromLong((long)st->st_mode));
+#ifdef HAVE_LARGEFILE_SUPPORT
+    PyStructSequence_SET_ITEM(v, 1,
+                              PyLong_FromLongLong((PY_LONG_LONG)st->st_ino));
+#else
+    PyStructSequence_SET_ITEM(v, 1, PyInt_FromLong((long)st->st_ino));
+#endif
+#if defined(HAVE_LONG_LONG) && !defined(MS_WINDOWS)
+    PyStructSequence_SET_ITEM(v, 2,
+                              PyLong_FromLongLong((PY_LONG_LONG)st->st_dev));
+#else
+    PyStructSequence_SET_ITEM(v, 2, PyInt_FromLong((long)st->st_dev));
+#endif
+    PyStructSequence_SET_ITEM(v, 3, PyInt_FromLong((long)st->st_nlink));
+    PyStructSequence_SET_ITEM(v, 4, PyInt_FromLong((long)st->st_uid));
+    PyStructSequence_SET_ITEM(v, 5, PyInt_FromLong((long)st->st_gid));
+#ifdef HAVE_LARGEFILE_SUPPORT
+    PyStructSequence_SET_ITEM(v, 6,
+                              PyLong_FromLongLong((PY_LONG_LONG)st->st_size));
+#else
+    PyStructSequence_SET_ITEM(v, 6, PyInt_FromLong(st->st_size));
+#endif
+
+#if defined(HAVE_STAT_TV_NSEC)
+    ansec = st->st_atim.tv_nsec;
+    mnsec = st->st_mtim.tv_nsec;
+    cnsec = st->st_ctim.tv_nsec;
+#elif defined(HAVE_STAT_TV_NSEC2)
+    ansec = st->st_atimespec.tv_nsec;
+    mnsec = st->st_mtimespec.tv_nsec;
+    cnsec = st->st_ctimespec.tv_nsec;
+#elif defined(HAVE_STAT_NSEC)
+    ansec = st->st_atime_nsec;
+    mnsec = st->st_mtime_nsec;
+    cnsec = st->st_ctime_nsec;
+#else
+    ansec = mnsec = cnsec = 0;
+#endif
+    fill_time(v, 7, st->st_atime, ansec);
+    fill_time(v, 8, st->st_mtime, mnsec);
+    fill_time(v, 9, st->st_ctime, cnsec);
+
+#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
+    PyStructSequence_SET_ITEM(v, ST_BLKSIZE_IDX,
+                              PyInt_FromLong((long)st->st_blksize));
+#endif
+#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
+    PyStructSequence_SET_ITEM(v, ST_BLOCKS_IDX,
+                              PyInt_FromLong((long)st->st_blocks));
+#endif
+#ifdef HAVE_STRUCT_STAT_ST_RDEV
+    PyStructSequence_SET_ITEM(v, ST_RDEV_IDX,
+                              PyInt_FromLong((long)st->st_rdev));
+#endif
+#ifdef HAVE_STRUCT_STAT_ST_GEN
+    PyStructSequence_SET_ITEM(v, ST_GEN_IDX,
+                              PyInt_FromLong((long)st->st_gen));
+#endif
+#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
+    {
+      PyObject *val;
+      unsigned long bsec,bnsec;
+      bsec = (long)st->st_birthtime;
+#ifdef HAVE_STAT_TV_NSEC2
+      bnsec = st->st_birthtimespec.tv_nsec;
+#else
+      bnsec = 0;
+#endif
+      val = PyFloat_FromDouble(bsec + 1e-9*bnsec);
+      PyStructSequence_SET_ITEM(v, ST_BIRTHTIME_IDX,
+                                val);
+    }
+#endif
+#ifdef HAVE_STRUCT_STAT_ST_FLAGS
+    PyStructSequence_SET_ITEM(v, ST_FLAGS_IDX,
+                              PyInt_FromLong((long)st->st_flags));
+#endif
+
+    if (PyErr_Occurred()) {
+        Py_DECREF(v);
+        return NULL;
+    }
+
+    return v;
+}