Chinaunix首页 | 论坛 | 博客
  • 博客访问: 176391
  • 博文数量: 13
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 832
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-16 22:43
个人简介

最近关注Python,Linux,LLVM

文章分类

全部博文(13)

文章存档

2014年(13)

分类: Python/Ruby

2014-03-03 10:18:25

(承接中篇)

C扩展的后半部分,包括特殊成员函数/类型定义与对象构造析构/模块定义与初始化

点击(此处)折叠或打开(inotifymodule.c)

  1. PyDoc_STRVAR(pyinotify_fileno_doc,
  2. "fileno() -> int\n\
  3. \n\
  4. Return the inotify file descriptor.");

  5. static PyObject*
  6. pyinotify_fileno(pyinotify *self)
  7. {
  8.     if (self->fd < 0)
  9.         return pyinotify_err_closed();
  10.     return PyLong_FromLong(self->fd);
  11. }

  12. static PyObject *
  13. new_pyinotify_object(PyTypeObject *type, int flags, int fd)
  14. {
  15.         pyinotify *self;

  16.         self = (pyinotify *)type->tp_alloc(type, 0);
  17.         if (self == NULL)
  18.                 return NULL;

  19.         if (fd == -1) {
  20.                 Py_BEGIN_ALLOW_THREADS
  21.                 self->fd = inotify_init1(flags);
  22.                 Py_END_ALLOW_THREADS
  23.         } else {
  24.                 self->fd = fd;
  25.         }
  26.         if (self->fd < 0) {
  27.                 Py_DECREF(self);
  28.                 PyErr_SetFromErrno(PyExc_OSError);
  29.                 return NULL;
  30.         }

  31.         return (PyObject *)self;
  32. }

  33. PyDoc_STRVAR(pyinotify_fromfd_doc,
  34. "fromfd(fd) -> inotify object. \n\
  35. \n\
  36. Create an inotify object from a given fd.");

  37. static PyObject*
  38. pyinotify_fromfd(PyObject *cls, PyObject *args)
  39. {
  40.     int fd;

  41.     if (!PyArg_ParseTuple(args, "i:fromfd", &fd))
  42.         return NULL;

  43.     return new_pyinotify_object((PyTypeObject*)cls, 0, fd);
  44. }

  45. static PyMethodDef pyinotify_methods[] = {
  46.         {"add_watch", (PyCFunction)pyinotify_add_watch,
  47.          METH_VARARGS, pyinotify_add_watch_doc},
  48.         {"rm_watch", (PyCFunction)pyinotify_rm_watch,
  49.          METH_VARARGS, pyinotify_rm_watch_doc},
  50.         {"read", (PyCFunction)pyinotify_read,
  51.          METH_VARARGS, pyinotify_read_doc},
  52.         {"read_events", (PyCFunction)pyinotify_read_events,
  53.          METH_VARARGS, pyinotify_read_events_doc},
  54.     {"fromfd", (PyCFunction)pyinotify_fromfd,
  55.      METH_VARARGS | METH_CLASS, pyinotify_fromfd_doc},
  56.     {"fileno", (PyCFunction)pyinotify_fileno,
  57.          METH_NOARGS, pyinotify_fileno_doc},
  58.         {"close", (PyCFunction)pyinotify_close,
  59.          METH_NOARGS, pyinotify_close_doc},
  60.         {NULL} /* Sentinel */
  61. };

  62. static PyGetSetDef pyepoll_getsetlist[] = {
  63.     {"closed", (getter)pyinotify_get_closed, NULL,
  64.      "True if the inotify instance is closed"},
  65.     {NULL},
  66. };

  67. static PyObject *
  68. pyinotify_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
  69. {
  70.         int flags = 0;
  71.         static char *kwlist[] = {"flags", NULL};

  72.         if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:inotify", kwlist,
  73.                                 &flags))
  74.                 return NULL;
  75.         
  76.     return new_pyinotify_object((PyTypeObject*)type, flags, -1);
  77. }

  78. static void
  79. pyinotify_dealloc(pyinotify* self)
  80. {
  81.         (void)pyinotify_internal_close(self);
  82.         Py_TYPE(self)->tp_free((PyObject*)self);
  83. }

  84. PyDoc_STRVAR(pyinotify_doc,
  85. "inotify object.\n\
  86. \n\
  87. The inotify API provides a mechanism for monitoring filesystem\n\
  88. events. Inotify can be used to monitor individual files, or to\n\
  89. monitor directories. When a directory is monitored, inotify will\n\
  90. return events for the directory itself, and for files inside the\n\
  91. directory.");

  92. static PyTypeObject pyinotify_type = {
  93.         PyVarObject_HEAD_INIT(NULL, 0)
  94.         "inotify.inotify", /* tp_name */
  95.         sizeof(pyinotify), /* tp_basicsize */
  96.         0, /* tp_itemsize */
  97.         (destructor)pyinotify_dealloc, /* tp_dealloc */
  98.         0, /* tp_print */
  99.         0, /* tp_getattr */
  100.         0, /* tp_setattr */
  101.         0, /* tp_reserved */
  102.         0, /* tp_repr */
  103.         0, /* tp_as_number */
  104.         0, /* tp_as_sequence */
  105.         0, /* tp_as_mapping */
  106.         0, /* tp_hash */
  107.         0, /* tp_call */
  108.         0, /* tp_str */
  109.         0, /* tp_getattro */
  110.         0, /* tp_setattro */
  111.         0, /* tp_as_buffer */
  112.         Py_TPFLAGS_DEFAULT |
  113.                 Py_TPFLAGS_BASETYPE, /* tp_flags */
  114.         pyinotify_doc, /* tp_doc */
  115.         0, /* tp_traverse */
  116.         0, /* tp_clear */
  117.         0, /* tp_richcompare */
  118.         0, /* tp_weaklistoffset */
  119.         0, /* tp_iter */
  120.         0, /* tp_iternext */
  121.         pyinotify_methods, /* tp_methods */
  122.         0, /* tp_members */
  123.         pyepoll_getsetlist, /* tp_getset */
  124.         0, /* tp_base */
  125.         0, /* tp_dict */
  126.         0, /* tp_descr_get */
  127.         0, /* tp_descr_set */
  128.         0, /* tp_dictoffset */
  129.         0, /* tp_init */
  130.         0, /* tp_alloc */
  131.         pyinotify_new, /* tp_new */
  132. };

  133. static PyModuleDef inotifymodule = {
  134.         PyModuleDef_HEAD_INIT,
  135.         "inotify",
  136.         "inotify - monitoring filesystem events",
  137.         -1,
  138.         NULL, NULL, NULL, NULL, NULL
  139. };

  140. PyMODINIT_FUNC
  141. PyInit_inotify(void)
  142. {
  143.         PyObject* m;

  144.         if (PyType_Ready(&pyinotify_type) < 0)
  145.                 return NULL;

  146.         m = PyModule_Create(&inotifymodule);
  147.         if (m == NULL)
  148.                 return NULL;

  149.         Py_INCREF(&pyinotify_type);
  150.         PyModule_AddObject(m, "inotify", (PyObject *)&pyinotify_type);

  151.         /* Supported events suitable for MASK parameter of INOTIFY_ADD_WATCH. */
  152.         PyModule_AddIntMacro(m, IN_ACCESS);
  153.         PyModule_AddIntMacro(m, IN_MODIFY);
  154.         PyModule_AddIntMacro(m, IN_ATTRIB);
  155.         PyModule_AddIntMacro(m, IN_CLOSE_WRITE);
  156.         PyModule_AddIntMacro(m, IN_CLOSE_NOWRITE);
  157.         PyModule_AddIntMacro(m, IN_CLOSE);
  158.         PyModule_AddIntMacro(m, IN_OPEN);
  159.         PyModule_AddIntMacro(m, IN_MOVED_FROM);
  160.         PyModule_AddIntMacro(m, IN_MOVED_TO);
  161.         PyModule_AddIntMacro(m, IN_MOVE);
  162.         PyModule_AddIntMacro(m, IN_CREATE);
  163.         PyModule_AddIntMacro(m, IN_DELETE);
  164.         PyModule_AddIntMacro(m, IN_DELETE_SELF);
  165.         PyModule_AddIntMacro(m, IN_MOVE_SELF);

  166.         /* Events sent by the kernel. */
  167.         PyModule_AddIntMacro(m, IN_UNMOUNT);
  168.         PyModule_AddIntMacro(m, IN_Q_OVERFLOW);
  169.         PyModule_AddIntMacro(m, IN_IGNORED);

  170.         /* Helper events. */
  171.         PyModule_AddIntMacro(m, IN_CLOSE);
  172.         PyModule_AddIntMacro(m, IN_MOVE);

  173.         /* Special flags. */
  174.         PyModule_AddIntMacro(m, IN_ONLYDIR);
  175.         PyModule_AddIntMacro(m, IN_DONT_FOLLOW);
  176.         PyModule_AddIntMacro(m, IN_EXCL_UNLINK);
  177.         PyModule_AddIntMacro(m, IN_MASK_ADD);
  178.         PyModule_AddIntMacro(m, IN_ISDIR);
  179.         PyModule_AddIntMacro(m, IN_ONESHOT);

  180.         /* All events which a program can wait on. */
  181.         PyModule_AddIntMacro(m, IN_ALL_EVENTS);
  182.  
  183.         /* supported flags for INOTIFY_INIT1. */
  184.         PyModule_AddIntMacro(m, IN_NONBLOCK);
  185.         PyModule_AddIntMacro(m, IN_CLOEXEC);

  186.         return m;
  187. }
这部分可以看作一个模板,大多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支持很复杂的定制,大家可以查文档。

点击(此处)折叠或打开(setup.py)

  1. from distutils.core import setup, Extension
  2. setup(name="inotify", version="1.0",
  3.       ext_modules=[
  4.          Extension("inotify", ["inotifymodule.c"]),
  5.       ])

第二步,编译&安装:
  1. (py3) bash-4.2 $python setup.py build
  2. running build
  3. running build_ext
  4. building 'inotify' extension
  5. 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
  6. 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
  7. (py3) bash-4.2 $python setup.py install
  8. running install
  9. running build
  10. running build_ext
  11. running install_lib
  12. copying build/lib.linux-i686-3.3/inotify.cpython-33m.so -> /home/lgr/venv/py3/lib/python3.3/site-packages
  13. running install_egg_info
  14. Removing /home/lgr/venv/py3/lib/python3.3/site-packages/inotify-1.0-py3.3.egg-info
  15. Writing /home/lgr/venv/py3/lib/python3.3/site-packages/inotify-1.0-py3.3.egg-info
第三步,测试,用本节开始的notify3.py,监控的事件和第五节一致,即编译第四节C代码过程中目录的变化:
  1. (py3) bash-4.2 $python notify3.py .
  2. 17:16:34,668 file(.) IN_ISDIR IN_OPEN
  3. 17:16:34,668 file(.) IN_CLOSE_NOWRITE IN_ISDIR
  4. 17:16:34,668 file(Makefile) IN_OPEN
  5. 17:16:34,668 file(Makefile) IN_ACCESS
  6. 17:16:34,668 file(Makefile) IN_CLOSE_NOWRITE
  7. 17:16:34,676 file(notify1.c) IN_OPEN
  8. 17:16:34,676 file(notify1.c) IN_ACCESS
  9. 17:16:34,676 file(notify1.c) IN_CLOSE_NOWRITE
  10. 17:16:34,712 file(notify1) IN_CREATE
  11. 17:16:34,712 file(notify1) IN_OPEN
  12. 17:16:34,716 file(notify1) IN_CLOSE_WRITE
  13. 17:16:34,722 file(notify1) IN_OPEN
  14. 17:16:34,722 file(notify1) IN_MODIFY
  15. ......
  16. 17:16:34,723 file(notify1) IN_MODIFY
  17. 17:16:34,723 file(notify1) IN_ACCESS
  18. 17:16:34,723 file(notify1) IN_MODIFY
  19. 17:16:34,723 file(notify1) IN_CLOSE_WRITE
  20. 17:16:34,723 file(notify1) IN_ATTRIB
  21. 17:16:37,148 file(.) IN_ISDIR IN_OPEN
  22. 17:16:37,148 file(.) IN_CLOSE_NOWRITE IN_ISDIR
  23. 17:16:37,148 file(Makefile) IN_OPEN
  24. 17:16:37,148 file(Makefile) IN_ACCESS
  25. 17:16:37,148 file(Makefile) IN_CLOSE_NOWRITE
  26. 17:16:37,149 file(notify1) IN_DELETE

七. 终章

   从产生想法,到编码实现,然后调试修改,最后写blog,差不多用了一周,终于完成,如释重负啊。本人比较喜欢APUE & UNPv1 & UNPv2讲述技术问题的方式,先引入简单的概念,然后给一个示例,并附上完整源码,接着分析相关的代码行,穿插讲解理论和隐藏细节,最后编译运行,同时观察输出并验证前面的理论与猜测,如果后面章节出现更高级的工具,重新实现前面章节的那个示例,循环往复,读者对概念的认识会比较深刻。但大师的境界往往是我等凡人可望不可即的,只能成此拙文一篇,错漏之处在所难免,欢迎大家批评指正

最后附上所有代码文件压缩包C代码,Makefile,Python代码

(全文完)
阅读(2622) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~