(承接中篇)
C扩展的后半部分,包括特殊成员函数/类型定义与对象构造析构/模块定义与初始化
点击(此处)折叠或打开(inotifymodule.c)
-
PyDoc_STRVAR(pyinotify_fileno_doc,
-
"fileno() -> int\n\
-
\n\
-
Return the inotify file descriptor.");
-
-
static PyObject*
-
pyinotify_fileno(pyinotify *self)
-
{
-
if (self->fd < 0)
-
return pyinotify_err_closed();
-
return PyLong_FromLong(self->fd);
-
}
-
-
static PyObject *
-
new_pyinotify_object(PyTypeObject *type, int flags, int fd)
-
{
-
pyinotify *self;
-
-
self = (pyinotify *)type->tp_alloc(type, 0);
-
if (self == NULL)
-
return NULL;
-
-
if (fd == -1) {
-
Py_BEGIN_ALLOW_THREADS
-
self->fd = inotify_init1(flags);
-
Py_END_ALLOW_THREADS
-
} else {
-
self->fd = fd;
-
}
-
if (self->fd < 0) {
-
Py_DECREF(self);
-
PyErr_SetFromErrno(PyExc_OSError);
-
return NULL;
-
}
-
-
return (PyObject *)self;
-
}
-
-
PyDoc_STRVAR(pyinotify_fromfd_doc,
-
"fromfd(fd) -> inotify object. \n\
-
\n\
-
Create an inotify object from a given fd.");
-
-
static PyObject*
-
pyinotify_fromfd(PyObject *cls, PyObject *args)
-
{
-
int fd;
-
-
if (!PyArg_ParseTuple(args, "i:fromfd", &fd))
-
return NULL;
-
-
return new_pyinotify_object((PyTypeObject*)cls, 0, fd);
-
}
-
-
static PyMethodDef pyinotify_methods[] = {
-
{"add_watch", (PyCFunction)pyinotify_add_watch,
-
METH_VARARGS, pyinotify_add_watch_doc},
-
{"rm_watch", (PyCFunction)pyinotify_rm_watch,
-
METH_VARARGS, pyinotify_rm_watch_doc},
-
{"read", (PyCFunction)pyinotify_read,
-
METH_VARARGS, pyinotify_read_doc},
-
{"read_events", (PyCFunction)pyinotify_read_events,
-
METH_VARARGS, pyinotify_read_events_doc},
-
{"fromfd", (PyCFunction)pyinotify_fromfd,
-
METH_VARARGS | METH_CLASS, pyinotify_fromfd_doc},
-
{"fileno", (PyCFunction)pyinotify_fileno,
-
METH_NOARGS, pyinotify_fileno_doc},
-
{"close", (PyCFunction)pyinotify_close,
-
METH_NOARGS, pyinotify_close_doc},
-
{NULL} /* Sentinel */
-
};
-
-
static PyGetSetDef pyepoll_getsetlist[] = {
-
{"closed", (getter)pyinotify_get_closed, NULL,
-
"True if the inotify instance is closed"},
-
{NULL},
-
};
-
-
static PyObject *
-
pyinotify_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-
{
-
int flags = 0;
-
static char *kwlist[] = {"flags", NULL};
-
-
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:inotify", kwlist,
-
&flags))
-
return NULL;
-
-
return new_pyinotify_object((PyTypeObject*)type, flags, -1);
-
}
-
-
static void
-
pyinotify_dealloc(pyinotify* self)
-
{
-
(void)pyinotify_internal_close(self);
-
Py_TYPE(self)->tp_free((PyObject*)self);
-
}
-
-
PyDoc_STRVAR(pyinotify_doc,
-
"inotify object.\n\
-
\n\
-
The inotify API provides a mechanism for monitoring filesystem\n\
-
events. Inotify can be used to monitor individual files, or to\n\
-
monitor directories. When a directory is monitored, inotify will\n\
-
return events for the directory itself, and for files inside the\n\
-
directory.");
-
-
static PyTypeObject pyinotify_type = {
-
PyVarObject_HEAD_INIT(NULL, 0)
-
"inotify.inotify", /* tp_name */
-
sizeof(pyinotify), /* tp_basicsize */
-
0, /* tp_itemsize */
-
(destructor)pyinotify_dealloc, /* tp_dealloc */
-
0, /* tp_print */
-
0, /* tp_getattr */
-
0, /* tp_setattr */
-
0, /* tp_reserved */
-
0, /* tp_repr */
-
0, /* tp_as_number */
-
0, /* tp_as_sequence */
-
0, /* tp_as_mapping */
-
0, /* tp_hash */
-
0, /* tp_call */
-
0, /* tp_str */
-
0, /* tp_getattro */
-
0, /* tp_setattro */
-
0, /* tp_as_buffer */
-
Py_TPFLAGS_DEFAULT |
-
Py_TPFLAGS_BASETYPE, /* tp_flags */
-
pyinotify_doc, /* tp_doc */
-
0, /* tp_traverse */
-
0, /* tp_clear */
-
0, /* tp_richcompare */
-
0, /* tp_weaklistoffset */
-
0, /* tp_iter */
-
0, /* tp_iternext */
-
pyinotify_methods, /* tp_methods */
-
0, /* tp_members */
-
pyepoll_getsetlist, /* tp_getset */
-
0, /* tp_base */
-
0, /* tp_dict */
-
0, /* tp_descr_get */
-
0, /* tp_descr_set */
-
0, /* tp_dictoffset */
-
0, /* tp_init */
-
0, /* tp_alloc */
-
pyinotify_new, /* tp_new */
-
};
-
-
static PyModuleDef inotifymodule = {
-
PyModuleDef_HEAD_INIT,
-
"inotify",
-
"inotify - monitoring filesystem events",
-
-1,
-
NULL, NULL, NULL, NULL, NULL
-
};
-
-
PyMODINIT_FUNC
-
PyInit_inotify(void)
-
{
-
PyObject* m;
-
-
if (PyType_Ready(&pyinotify_type) < 0)
-
return NULL;
-
-
m = PyModule_Create(&inotifymodule);
-
if (m == NULL)
-
return NULL;
-
-
Py_INCREF(&pyinotify_type);
-
PyModule_AddObject(m, "inotify", (PyObject *)&pyinotify_type);
-
-
/* Supported events suitable for MASK parameter of INOTIFY_ADD_WATCH. */
-
PyModule_AddIntMacro(m, IN_ACCESS);
-
PyModule_AddIntMacro(m, IN_MODIFY);
-
PyModule_AddIntMacro(m, IN_ATTRIB);
-
PyModule_AddIntMacro(m, IN_CLOSE_WRITE);
-
PyModule_AddIntMacro(m, IN_CLOSE_NOWRITE);
-
PyModule_AddIntMacro(m, IN_CLOSE);
-
PyModule_AddIntMacro(m, IN_OPEN);
-
PyModule_AddIntMacro(m, IN_MOVED_FROM);
-
PyModule_AddIntMacro(m, IN_MOVED_TO);
-
PyModule_AddIntMacro(m, IN_MOVE);
-
PyModule_AddIntMacro(m, IN_CREATE);
-
PyModule_AddIntMacro(m, IN_DELETE);
-
PyModule_AddIntMacro(m, IN_DELETE_SELF);
-
PyModule_AddIntMacro(m, IN_MOVE_SELF);
-
-
/* Events sent by the kernel. */
-
PyModule_AddIntMacro(m, IN_UNMOUNT);
-
PyModule_AddIntMacro(m, IN_Q_OVERFLOW);
-
PyModule_AddIntMacro(m, IN_IGNORED);
-
-
/* Helper events. */
-
PyModule_AddIntMacro(m, IN_CLOSE);
-
PyModule_AddIntMacro(m, IN_MOVE);
-
-
/* Special flags. */
-
PyModule_AddIntMacro(m, IN_ONLYDIR);
-
PyModule_AddIntMacro(m, IN_DONT_FOLLOW);
-
PyModule_AddIntMacro(m, IN_EXCL_UNLINK);
-
PyModule_AddIntMacro(m, IN_MASK_ADD);
-
PyModule_AddIntMacro(m, IN_ISDIR);
-
PyModule_AddIntMacro(m, IN_ONESHOT);
-
-
/* All events which a program can wait on. */
-
PyModule_AddIntMacro(m, IN_ALL_EVENTS);
-
-
/* supported flags for INOTIFY_INIT1. */
-
PyModule_AddIntMacro(m, IN_NONBLOCK);
-
PyModule_AddIntMacro(m, IN_CLOEXEC);
-
-
return m;
-
}
这部分可以看作一个模板,大多C扩展都是这个框架
行1~12:特殊成员函数fileno,直接返回file descriptor,这基本是Python标准库的惯例了,所有封装file descriptor的类型都提供这个方法。
行39~53:特殊成员函数fromfd,根据已有fd,构造一个inotify对象,也是标准库的一个惯例。
行55~71:类型定义之一,成员函数定义表,Python就是通过该结构动态查找到对应的C函数,进而调用之。
行73~77:类型定义之一,属性定义表,inotify只定义了一个closed只读属性,判断fd是否关闭。
行79~90:类型对象的构造,相当于object.__new__,分配内存并提供必要的初始化,
对象的reference count自动加1。
行92~97:类型对象的析构,与构造相反,清理一些外部资源(fd),释放内存,当对象的reference count为0时,就会调用该方法。
行99~148:类型定义最高层入口,索引一切类型信息,上面成员函数表/属性定义/对象构造析构函数都是其中的条目。
行150~156:模块定义,通常模块只是内部类型的容器,本身功能不多,从参数就可以看出来。
行158~215:模块初始化,这是整个模块内唯一的非静态函数,解释器加载模块的唯一入口。此处基本执行顺序就是初始化类型定义,初始化模块,然后模块载入类型定义,并添加了很多模块层的常量。
3. C扩展的编译 & 安装 & 测试。Python 3.3有一个比较有用的特性virtual environments,能以普通用户权限创建一个轻量级的虚拟环境,编译安装测试第三方模块很方便,不用自己再折腾环境变量和符号链接了,用法见,下面的测试就是基于Python 3.3的虚拟环境。
第一步,准备setup.py,供编译安装用,本文只用了几个参数,所以极其简单,其实setup.py支持很复杂的定制,大家可以查文档。
-
from distutils.core import setup, Extension
-
setup(name="inotify", version="1.0",
-
ext_modules=[
-
Extension("inotify", ["inotifymodule.c"]),
-
])
第二步,编译&安装:
-
(py3) bash-4.2 $python setup.py build
-
running build
-
running build_ext
-
building 'inotify' extension
-
gcc -pthread -Wno-unused-result -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m32 -march=i686 -mtune=atom -fasynchronous-unwind-tables -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I/home/lgr/venv/py3/include -I/usr/include/python3.3m -c inotifymodule.c -o build/temp.linux-i686-3.3/inotifymodule.o
-
gcc -pthread -shared -Wl,-z,relro build/temp.linux-i686-3.3/inotifymodule.o -L/usr/lib -lpython3.3m -o build/lib.linux-i686-3.3/inotify.cpython-33m.so
-
(py3) bash-4.2 $python setup.py install
-
running install
-
running build
-
running build_ext
-
running install_lib
-
copying build/lib.linux-i686-3.3/inotify.cpython-33m.so -> /home/lgr/venv/py3/lib/python3.3/site-packages
-
running install_egg_info
-
Removing /home/lgr/venv/py3/lib/python3.3/site-packages/inotify-1.0-py3.3.egg-info
-
Writing /home/lgr/venv/py3/lib/python3.3/site-packages/inotify-1.0-py3.3.egg-info
第三步,测试,用本节开始的notify3.py,监控的事件和第五节一致,即编译第四节C代码过程中目录的变化:
-
(py3) bash-4.2 $python notify3.py .
-
17:16:34,668 file(.) IN_ISDIR IN_OPEN
-
17:16:34,668 file(.) IN_CLOSE_NOWRITE IN_ISDIR
-
17:16:34,668 file(Makefile) IN_OPEN
-
17:16:34,668 file(Makefile) IN_ACCESS
-
17:16:34,668 file(Makefile) IN_CLOSE_NOWRITE
-
17:16:34,676 file(notify1.c) IN_OPEN
-
17:16:34,676 file(notify1.c) IN_ACCESS
-
17:16:34,676 file(notify1.c) IN_CLOSE_NOWRITE
-
17:16:34,712 file(notify1) IN_CREATE
-
17:16:34,712 file(notify1) IN_OPEN
-
17:16:34,716 file(notify1) IN_CLOSE_WRITE
-
17:16:34,722 file(notify1) IN_OPEN
-
17:16:34,722 file(notify1) IN_MODIFY
-
......
-
17:16:34,723 file(notify1) IN_MODIFY
-
17:16:34,723 file(notify1) IN_ACCESS
-
17:16:34,723 file(notify1) IN_MODIFY
-
17:16:34,723 file(notify1) IN_CLOSE_WRITE
-
17:16:34,723 file(notify1) IN_ATTRIB
-
17:16:37,148 file(.) IN_ISDIR IN_OPEN
-
17:16:37,148 file(.) IN_CLOSE_NOWRITE IN_ISDIR
-
17:16:37,148 file(Makefile) IN_OPEN
-
17:16:37,148 file(Makefile) IN_ACCESS
-
17:16:37,148 file(Makefile) IN_CLOSE_NOWRITE
-
17:16:37,149 file(notify1) IN_DELETE
七. 终章
从产生想法,到编码实现,然后调试修改,最后写blog,
差不多用了一周,终于完成,如释重负啊。
本人比较喜欢APUE & UNPv1 & UNPv2讲述技术问题的方式,先引入简单的概念,然后给一个示例,并附上完整源码,接着分析相关的代码行,穿插讲解理论和隐藏细节,最后编译运行,同时观察输出并验证前面的理论与猜测,如果后面章节出现更高级的工具,重新实现前面章节的那个示例,循环往复,读者对概念的认识会比较深刻。但大师的境界往往是我等凡人可望不可即的,只能成此拙文一篇,错漏之处在所难免,欢迎大家批评指正。
最后附上所有代码文件压缩包
C代码,Makefile,Python代码
(全文完)
阅读(2669) | 评论(0) | 转发(1) |