├── .gitignore ├── LICENSE ├── README.rst ├── setup.py └── src └── c10k ├── C10kPthread.pyx ├── C10kPthread.setup ├── C10kSocket.pyx ├── C10kSocket.setup ├── Makefile ├── __init__.py ├── __main__.py ├── _gevent_cgreenlet.h ├── libc10k.c ├── libc10k.setup └── pthread.pxd /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies of this 6 | license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates the 10 | terms and conditions of version 3 of the GNU General Public License, 11 | supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, other than 20 | an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided by the 23 | Library, but which is not otherwise based on the Library. Defining a 24 | subclass of a class defined by the Library is deemed a mode of using an 25 | interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an Application 28 | with the Library. The particular version of the Library with which the 29 | Combined Work was made is also called the "Linked Version". 30 | 31 | The "Minimal Corresponding Source" for a Combined Work means the 32 | Corresponding Source for the Combined Work, excluding any source code for 33 | portions of the Combined Work that, considered in isolation, are based on 34 | the Application, and not on the Linked Version. 35 | 36 | The "Corresponding Application Code" for a Combined Work means the object 37 | code and/or source code for the Application, including any data and utility 38 | programs needed for reproducing the Combined Work from the Application, but 39 | excluding the System Libraries of the Combined Work. 40 | 41 | 1. Exception to Section 3 of the GNU GPL. 42 | 43 | You may convey a covered work under sections 3 and 4 of this License 44 | without being bound by section 3 of the GNU GPL. 45 | 46 | 2. Conveying Modified Versions. 47 | 48 | If you modify a copy of the Library, and, in your modifications, a facility 49 | refers to a function or data to be supplied by an Application that uses the 50 | facility (other than as an argument passed when the facility is invoked), 51 | then you may convey a copy of the modified version: 52 | 53 | a) under this License, provided that you make a good faith effort to 54 | ensure that, in the event an Application does not supply the function 55 | or data, the facility still operates, and performs whatever part of its 56 | purpose remains meaningful, or 57 | 58 | b) under the GNU GPL, with none of the additional permissions of this 59 | License applicable to that copy. 60 | 61 | 3. Object Code Incorporating Material from Library Header Files. 62 | 63 | The object code form of an Application may incorporate material from a 64 | header file that is part of the Library. You may convey such object code 65 | under terms of your choice, provided that, if the incorporated material is 66 | not limited to numerical parameters, data structure layouts and accessors, 67 | or small macros, inline functions and templates (ten or fewer lines in 68 | length), you do both of the following: 69 | 70 | a) Give prominent notice with each copy of the object code that the 71 | Library is used in it and that the Library and its use are covered by 72 | this License. 73 | 74 | b) Accompany the object code with a copy of the GNU GPL and this 75 | license document. 76 | 77 | 4. Combined Works. 78 | 79 | You may convey a Combined Work under terms of your choice that, taken 80 | together, effectively do not restrict modification of the portions of the 81 | Library contained in the Combined Work and reverse engineering for 82 | debugging such modifications, if you also do each of the following: 83 | 84 | a) Give prominent notice with each copy of the Combined Work that the 85 | Library is used in it and that the Library and its use are covered by 86 | this License. 87 | 88 | b) Accompany the Combined Work with a copy of the GNU GPL and this 89 | license document. 90 | 91 | c) For a Combined Work that displays copyright notices during 92 | execution, include the copyright notice for the Library among these 93 | notices, as well as a reference directing the user to the copies of the 94 | GNU GPL and this license document. 95 | 96 | d) Do one of the following: 97 | 98 | 0) Convey the Minimal Corresponding Source under the terms of this 99 | License, and the Corresponding Application Code in a form suitable 100 | for, and under terms that permit, the user to recombine or relink 101 | the Application with a modified version of the Linked Version to 102 | produce a modified Combined Work, in the manner specified by 103 | section 6 of the GNU GPL for conveying Corresponding Source. 104 | 105 | 1) Use a suitable shared library mechanism for linking with the 106 | Library. A suitable mechanism is one that (a) uses at run time 107 | a copy of the Library already present on the user's computer 108 | system, and (b) will operate properly with a modified version of 109 | the Library that is interface-compatible with the Linked Version. 110 | 111 | e) Provide Installation Information, but only if you would otherwise 112 | be required to provide such information under section 6 of the GNU GPL, 113 | and only to the extent that such information is necessary to install 114 | and execute a modified version of the Combined Work produced by 115 | recombining or relinking the Application with a modified version of the 116 | Linked Version. (If you use option 4d0, the Installation Information 117 | must accompany the Minimal Corresponding Source and Corresponding 118 | Application Code. If you use option 4d1, you must provide the 119 | Installation Information in the manner specified by section 6 of the 120 | GNU GPL for conveying Corresponding Source.) 121 | 122 | 5. Combined Libraries. 123 | 124 | You may place library facilities that are a work based on the Library side 125 | by side in a single library together with other library facilities that are 126 | not Applications and are not covered by this License, and convey such a 127 | combined library under terms of your choice, if you do both of the 128 | following: 129 | 130 | a) Accompany the combined library with a copy of the same work based on 131 | the Library, uncombined with any other library facilities, conveyed 132 | under the terms of this License. 133 | 134 | b) Give prominent notice with the combined library that part of it is a 135 | work based on the Library, and explaining where to find the 136 | accompanying uncombined form of the same work. 137 | 138 | 6. Revised Versions of the GNU Lesser General Public License. 139 | 140 | The Free Software Foundation may publish revised and/or new versions of the 141 | GNU Lesser General Public License from time to time. Such new versions will 142 | be similar in spirit to the present version, but may differ in detail to 143 | address new problems or concerns. 144 | 145 | Each version is given a distinguishing version number. If the Library as 146 | you received it specifies that a certain numbered version of the GNU Lesser 147 | General Public License "or any later version" applies to it, you have the 148 | option of following the terms and conditions either of that published 149 | version or of any later version published by the Free Software Foundation. 150 | If the Library as you received it does not specify a version number of the 151 | GNU Lesser General Public License, you may choose any version of the GNU 152 | Lesser General Public License ever published by the Free Software 153 | Foundation. 154 | 155 | If the Library as you received it specifies that a proxy can decide whether 156 | future versions of the GNU Lesser General Public License shall apply, that 157 | proxy's public statement of acceptance of any version is permanent 158 | authorization for you to choose that version for the Library. 159 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ========= 2 | C10K plan 3 | ========= 4 | 5 | Introduction 6 | ------------ 7 | 8 | C10K is a coroutine-based alternative implementation of the posix thread. 9 | It allows existing non-asynchronous programs, regardless of the programming 10 | language they use, to become coroutine-based asynchronous programs without 11 | any modifications, and makes it possible for programs to handle a large 12 | number of clients at the same time. 13 | 14 | At this moment C10K is still under heavy development. 15 | 16 | 17 | Usage 18 | ----- 19 | 20 | The **c10k** command can start a specified program that runs 21 | asynchronously. 22 | 23 | .. code-block:: console 24 | 25 | $ c10k ab -c 1000 -n 10000 http://example.com/ 26 | 27 | .. code-block:: console 28 | 29 | $ c10k bash 30 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import re 4 | import setuptools 5 | 6 | with open('src/c10k/__init__.py') as f: 7 | version = re.search(r"__version__\s*=\s*'(.*)'", f.read()).group(1) 8 | with open('README.rst') as f: 9 | readme = f.read() 10 | 11 | setuptools.setup( 12 | name='c10k', 13 | version=version, 14 | description='', 15 | long_description=readme, 16 | license='LGPLv3', 17 | keywords='', 18 | author='Wilhelm Shen', 19 | author_email='wilhelmshen@pyforce.com', 20 | url='http://c10k.pyforce.com', 21 | package_dir={'': 'src'}, 22 | packages=['c10k'], 23 | install_requires= 24 | [ 25 | 'gevent>=20.4.0' 26 | ] 27 | classifiers= 28 | [ 29 | 'License :: OSI Approved :: GNU Lesser General Public '+ 30 | 'License v3 (LGPLv3)', 31 | 'Programming Language :: Python :: 3.6', 32 | 'Programming Language :: Python :: 3.7', 33 | 'Programming Language :: Python :: 3.8', 34 | 'Programming Language :: Python :: 3.9', 35 | 'Programming Language :: Python :: Implementation :: '+ 36 | 'CPython', 37 | 'Operating System :: POSIX', 38 | 'Topic :: Internet', 39 | 'Topic :: Software Development :: Libraries :: '+ 40 | 'Python Modules', 41 | 'Intended Audience :: Developers', 42 | 'Development Status :: 1 - Planning' 43 | ], 44 | python_requires='>=3.6', 45 | entry_points= 46 | { 47 | 'console_scripts': ['c10k=c10k.__main__:main'] 48 | } 49 | ) 50 | -------------------------------------------------------------------------------- /src/c10k/C10kPthread.pyx: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # cython: language_level=3 3 | 4 | cimport cpython.mem 5 | cimport cpython.object 6 | cimport cpython.pycapsule 7 | cimport cpython.ref 8 | cimport cython 9 | cimport libc.errno 10 | cimport libc.stdint 11 | cimport libc.stdio 12 | cimport libc.stdlib 13 | cimport posix.time 14 | cimport posix.types 15 | 16 | from pthread cimport * 17 | 18 | cdef extern from '': 19 | 20 | enum: 21 | EDEADLK, # 35 Resource deadlock would occur 22 | # for robust mutexes 23 | EOWNERDEAD # 130 Owner died 24 | 25 | cdef extern from '': 26 | 27 | cpython.object.PyObject* _PyObject_CallMethod \ 28 | 'PyObject_CallMethod' \ 29 | ( 30 | cpython.object.PyObject *, 31 | char *, 32 | ... 33 | ) nogil 34 | 35 | cdef extern from '': 36 | 37 | ctypedef struct PyGreenlet: 38 | 39 | char* stack_start 40 | PyGreenlet* parent 41 | cpython.object.PyObject* run_info 42 | 43 | ctypedef class greenlet.greenlet [object PyGreenlet]: 44 | 45 | cdef greenlet parent 46 | cdef object run_info 47 | 48 | greenlet PyGreenlet_GetCurrent() 49 | 50 | cdef extern from '_gevent_cgreenlet.h': 51 | 52 | ctypedef struct PyC10kGeventGreenlet: 53 | 54 | PyGreenlet __pyx_base 55 | void * __pyx_vtab 56 | cpython.object.PyObject *value 57 | cpython.object.PyObject *args 58 | cpython.object.PyObject *kwargs 59 | cpython.object.PyObject *spawning_greenlet 60 | cpython.object.PyObject *spawning_stack 61 | cpython.object.PyObject *spawn_tree_locals 62 | cpython.object.PyObject *_links 63 | cpython.object.PyObject *_exc_info 64 | cpython.object.PyObject *_notifier 65 | cpython.object.PyObject *_start_event 66 | cpython.object.PyObject *_formatted_info 67 | cpython.object.PyObject *_ident 68 | 69 | ctypedef class gevent._greenlet.Greenlet [object PyC10kGeventGreenlet]: 70 | 71 | cdef object value 72 | cdef object args 73 | cdef object kwargs 74 | cdef object spawning_greenlet 75 | cdef object spawning_stack 76 | cdef object spawn_tree_locals 77 | cdef object _links 78 | cdef object _exc_info 79 | cdef object _notifier 80 | cdef object _start_event 81 | cdef object _formatted_info 82 | cdef object _ident 83 | 84 | cdef extern from 'C10kPthread.h': 85 | 86 | cpython.object.PyObject* __pyx_empty_tuple 87 | cpython.object.PyObject* __Pyx_PyObject_CallOneArg \ 88 | ( 89 | cpython.object.PyObject *, 90 | cpython.object.PyObject * 91 | ) 92 | 93 | cdef public int C10kPthread_initialized = 0 94 | cdef int __concurrency_level = 0 95 | cdef void *__key_limbo_specific 96 | cdef pthread_key_t __key_limbo = 0 97 | cdef pthread_once_t ONCE_DONE = -1 98 | cdef pthread_t TH_MAIN = 0 99 | 100 | ########################################################################### 101 | 102 | import gevent 103 | import gevent._greenlet 104 | import gevent.event 105 | import gevent.local 106 | import gevent.lock 107 | import gevent.os 108 | import gevent.queue 109 | import sys 110 | import time 111 | import weakref 112 | 113 | from gevent._greenlet import Greenlet 114 | 115 | dummy_event_finder = gevent.Greenlet(lambda: None) 116 | dummy_event_finder.throw(gevent.GreenletExit) 117 | _cancelled_start_event = (dummy_event_finder)._start_event 118 | dummy_event_finder = gevent.Greenlet(lambda: None) 119 | dummy_event_finder.start() 120 | dummy_event_finder.join() 121 | _start_completed_event = (dummy_event_finder)._start_event 122 | del dummy_event_finder 123 | g_main = gevent.getcurrent() 124 | greenlets = \ 125 | { 126 | TH_MAIN : g_main, 127 | g_main: g_main 128 | } 129 | mutexes = {} 130 | rwlocks = {} 131 | conds = {} 132 | barriers = {} 133 | atfork_prepare = [] 134 | atfork_parent = [] 135 | atfork_child = [] 136 | __local = gevent.local.local() 137 | LOCAL_KEY = 'C10kPthreadKey' 138 | sys.setswitchinterval(0xffffffff) 139 | 140 | ########################################################################### 141 | 142 | cdef class Attr: 143 | 144 | cdef int detachstate 145 | cdef size_t guardsize 146 | cdef sched_param schedparam 147 | cdef int schedpolicy 148 | cdef int inheritsched 149 | cdef int scope 150 | cdef void *stackaddr 151 | cdef size_t stacksize 152 | 153 | cdef int init(self, const pthread_attr_t *attr): 154 | if NULL == attr: 155 | return self.set_default() 156 | else: 157 | return self.set(attr) 158 | 159 | cdef int set_default(self): 160 | cdef pthread_attr_t attr 161 | cdef int fail = pthread_attr_init(&attr) 162 | if fail: 163 | return fail 164 | return self.set(&attr) 165 | 166 | cdef int set(self, const pthread_attr_t *attr): 167 | cdef int fail 168 | fail = pthread_attr_getdetachstate(attr, &self.detachstate) 169 | if fail: 170 | return fail 171 | fail = pthread_attr_getguardsize(attr, &self.guardsize) 172 | if fail: 173 | return fail 174 | fail = pthread_attr_getschedparam(attr, &self.schedparam) 175 | if fail: 176 | return fail 177 | fail = pthread_attr_getschedpolicy(attr, &self.schedpolicy) 178 | if fail: 179 | return fail 180 | fail = pthread_attr_getinheritsched(attr, &self.inheritsched) 181 | if fail: 182 | return fail 183 | fail = pthread_attr_getscope(attr, &self.scope) 184 | if fail: 185 | return fail 186 | fail = \ 187 | pthread_attr_getstack( 188 | attr, 189 | &self.stackaddr, 190 | &self.stacksize 191 | ) 192 | if fail: 193 | return fail 194 | return 0 195 | 196 | cdef int get(self, pthread_attr_t *attr): 197 | cdef int fail 198 | fail = pthread_attr_setdetachstate(attr, self.detachstate) 199 | if fail: 200 | return fail 201 | fail = pthread_attr_setguardsize(attr, self.guardsize) 202 | if fail: 203 | return fail 204 | fail = pthread_attr_setschedparam(attr, &self.schedparam) 205 | if fail != 0: 206 | return fail 207 | fail = pthread_attr_setschedpolicy(attr, self.schedpolicy) 208 | if fail != 0: 209 | return fail 210 | fail = pthread_attr_setinheritsched(attr, self.inheritsched) 211 | if fail != 0: 212 | return fail 213 | fail = pthread_attr_setscope(attr, self.scope) 214 | if fail != 0: 215 | return fail 216 | fail = pthread_attr_setstack(attr, self.stackaddr, self.stacksize) 217 | if fail: 218 | return fail 219 | return 0 220 | 221 | cdef class Thread: 222 | 223 | cdef bytes name 224 | cdef Attr attr 225 | cdef int cancelstate 226 | cdef int canceltype 227 | cdef void *(*start_routine) (void *) nogil 228 | cdef void *arg 229 | cdef void *retval 230 | 231 | cdef int init \ 232 | ( 233 | self, 234 | bytes name, 235 | Attr attr, 236 | void *(*start_routine) (void *) nogil, 237 | void *arg 238 | ): 239 | self.name = name 240 | self.attr = attr 241 | self.cancelstate = PTHREAD_CANCEL_DISABLE 242 | self.canceltype = PTHREAD_CANCEL_DEFERRED 243 | self.start_routine = start_routine 244 | self.arg = arg 245 | self.retval = NULL 246 | return 0 247 | 248 | def run(): 249 | g = gevent.getcurrent() 250 | if g._start_event is None: 251 | g._start_event = _cancelled_start_event 252 | g._start_event.stop() 253 | g._start_event.close() 254 | g._start_event = _start_completed_event 255 | t = g.args[0] 256 | cdef void *start_routine = t.start_routine 257 | cdef void *arg = t.arg 258 | del t 259 | del g 260 | cdef void *retval = (start_routine)(arg) 261 | g = gevent.getcurrent() 262 | t = g.args[0] 263 | key = \ 264 | \ 265 | \ 266 | g 267 | t.retval = retval 268 | g._exc_info = (None, None, None) 269 | g.value = None 270 | if g._links and not g._notifier: 271 | g._notifier = (g) \ 272 | . parent \ 273 | . loop \ 274 | . run_callback(g._notify_links) 275 | del g.run 276 | g.args = () 277 | g.kwargs.clear() 278 | del greenlets[key] 279 | 280 | # Create a new thread, starting with execution of START-ROUTINE 281 | # getting passed ARG. Creation attributed come from ATTR. The new 282 | # handle is stored in *NEWTHREAD. 283 | cdef public int pthread_create \ 284 | ( 285 | pthread_t *newthread, 286 | const pthread_attr_t *attr, 287 | void *(*start_routine) (void *) nogil, 288 | void *arg 289 | ): 290 | pAttr = Attr() 291 | cdef int fail = pAttr.init(attr) 292 | if fail: 293 | return fail 294 | t = Thread() 295 | g = Greenlet() 296 | t.init(g.name.encode(), pAttr, start_routine, arg) 297 | g.run = run 298 | g.args = (t, ) 299 | g.start() 300 | key = \ 301 | \ 302 | \ 303 | g 304 | greenlets[key] = g 305 | newthread[0] = \ 306 | \ 307 | \ 308 | g 309 | return 0 310 | 311 | # Terminate calling thread. 312 | # 313 | # The registered cleanup handlers are called via exception handling 314 | # so we cannot mark this function with __THROW. 315 | cdef public void pthread_exit(void *retval): 316 | g = gevent.getcurrent() 317 | cdef pthread_t th = \ 318 | \ 319 | \ 320 | g 321 | del g 322 | __cancel(th, retval) 323 | 324 | cdef void __cancel(pthread_t th, void *retval): 325 | key = th 326 | g = greenlets[key] 327 | t = g.args[0] 328 | if retval != NULL: 329 | t.retval = retval 330 | g._exc_info = (None, None, None) 331 | g.value = None 332 | if g._links and not g._notifier: 333 | g._notifier = (g) \ 334 | . parent \ 335 | . loop \ 336 | . run_callback(g._notify_links) 337 | g.args = () 338 | g.kwargs.clear() 339 | del g.run 340 | del greenlets[key] 341 | del t 342 | del key 343 | cdef cpython.object.PyObject *pMyHub = \ 344 | (g).parent 345 | (g).stack_start = NULL 346 | del g 347 | # XXX 348 | _PyObject_CallMethod(pMyHub, b'switch', NULL) 349 | 350 | # Make calling thread wait for termination of the thread TH. The 351 | # exit status of the thread is stored in *THREAD_RETURN, if THREAD_RETURN 352 | # is not NULL. 353 | # 354 | # This function is a cancellation point and therefore not marked with 355 | # __THROW. 356 | cdef public int pthread_join(pthread_t th, void **thread_return): 357 | key = th 358 | try: 359 | g = greenlets[key] 360 | except KeyError: 361 | return libc.errno.ESRCH 362 | try: 363 | t = g.args[0] 364 | except TypeError: 365 | return libc.errno.ESRCH 366 | if t.attr.detachstate != PTHREAD_CREATE_JOINABLE: 367 | return libc.errno.EINVAL 368 | g.join() 369 | if thread_return != NULL: 370 | thread_return = &t.retval 371 | return 0 372 | 373 | # Check whether thread TH has terminated. If yes return the status of 374 | # the thread in *THREAD_RETURN, if THREAD_RETURN is not NULL. 375 | cdef public int pthread_tryjoin_np(pthread_t th, void **thread_return): 376 | key = th 377 | try: 378 | g = greenlets[key] 379 | except KeyError: 380 | return libc.errno.ESRCH 381 | try: 382 | t = g.args[0] 383 | except TypeError: 384 | return libc.errno.ESRCH 385 | if t.attr.detachstate != PTHREAD_CREATE_JOINABLE: 386 | return libc.errno.EINVAL 387 | if g.ready(): 388 | if thread_return != NULL: 389 | thread_return = &t.retval 390 | return 0 391 | else: 392 | return libc.errno.EBUSY 393 | 394 | # Make calling thread wait for termination of the thread TH, but only 395 | # until TIMEOUT. The exit status of the thread is stored in 396 | # *THREAD_RETURN, if THREAD_RETURN is not NULL. 397 | # 398 | # This function is a cancellation point and therefore not marked with 399 | # __THROW. 400 | cdef public int pthread_timedjoin_np \ 401 | ( 402 | pthread_t th, 403 | void **thread_return, 404 | const posix.time.timespec *abstime 405 | ): 406 | key = th 407 | try: 408 | g = greenlets[key] 409 | except KeyError: 410 | return libc.errno.ESRCH 411 | try: 412 | t = g.args[0] 413 | except TypeError: 414 | return libc.errno.ESRCH 415 | if t.attr.detachstate != PTHREAD_CREATE_JOINABLE: 416 | return libc.errno.EINVAL 417 | g.join(timeout=max(abstime.tv_sec-int(time.time()), 0)) 418 | if g.ready(): 419 | if thread_return != NULL: 420 | thread_return = &t.retval 421 | return 0 422 | else: 423 | return libc.errno.ETIMEDOUT 424 | 425 | # Indicate that the thread TH is never to be joined with PTHREAD_JOIN. 426 | # The resources of TH will therefore be freed immediately when it 427 | # terminates, instead of waiting for another thread to perform PTHREAD_JOIN 428 | # on it. 429 | cdef public int pthread_detach(pthread_t th): 430 | key = th 431 | try: 432 | g = greenlets[key] 433 | except KeyError: 434 | return libc.errno.ESRCH 435 | try: 436 | t = g.args[0] 437 | except TypeError: 438 | return libc.errno.ESRCH 439 | t.attr.detachstate = PTHREAD_CREATE_DETACHED 440 | return 0 441 | 442 | # Obtain the identifier of the current thread. 443 | cdef public pthread_t pthread_self(): 444 | cdef pthread_t th 445 | if C10kPthread_initialized: 446 | g = gevent.getcurrent() 447 | if g is g_main: 448 | return TH_MAIN 449 | else: 450 | th = \ 451 | \ 452 | \ 453 | g 454 | return th 455 | else: 456 | return TH_MAIN 457 | 458 | # Compare two thread identifiers. 459 | cdef public int pthread_equal(pthread_t thread1, pthread_t thread2): 460 | key1 = thread1 461 | key2 = thread2 462 | if key1 == key2: 463 | if key1 in greenlets: 464 | return 1 465 | else: 466 | return libc.errno.ESRCH 467 | else: 468 | if key1 not in greenlets: 469 | return libc.errno.ESRCH 470 | elif key2 not in greenlets: 471 | return libc.errno.ESRCH 472 | else: 473 | return 0 474 | 475 | ########################################################################### 476 | # Thread attribute handling. # 477 | ########################################################################### 478 | 479 | # Initialize thread attribute *ATTR with attributes corresponding to the 480 | # already running thread TH. It shall be called on uninitialized ATTR 481 | # and destroyed with pthread_attr_destroy when no longer needed. 482 | cdef public int pthread_getattr_np(pthread_t th, pthread_attr_t *attr): 483 | key = th 484 | try: 485 | g = greenlets[key] 486 | except KeyError: 487 | return libc.errno.ESRCH 488 | try: 489 | t = g.args[0] 490 | except TypeError: 491 | return libc.errno.ESRCH 492 | return t.attr.get(attr) 493 | 494 | ########################################################################### 495 | # Functions for scheduling control. # 496 | ########################################################################### 497 | 498 | # Set the scheduling parameters for TARGET_THREAD according to POLICY 499 | # and *PARAM. 500 | cdef public int pthread_setschedparam \ 501 | ( 502 | pthread_t target_thread, 503 | int policy, 504 | const sched_param *param 505 | ): 506 | key = target_thread 507 | try: 508 | g = greenlets[key] 509 | except KeyError: 510 | return libc.errno.ESRCH 511 | try: 512 | t = g.args[0] 513 | except TypeError: 514 | return libc.errno.ESRCH 515 | t.schedpolicy = policy 516 | t.schedparam.sched_priority = param.sched_priority 517 | return 0 518 | 519 | # Return in *POLICY and *PARAM the scheduling parameters for TARGET_THREAD. 520 | cdef public int pthread_getschedparam \ 521 | ( 522 | pthread_t target_thread, 523 | int *policy, 524 | sched_param *param 525 | ): 526 | key = target_thread 527 | try: 528 | g = greenlets[key] 529 | except KeyError: 530 | return libc.errno.ESRCH 531 | try: 532 | t = g.args[0] 533 | except TypeError: 534 | return libc.errno.ESRCH 535 | policy[0] = t.schedpolicy 536 | param.sched_priority = t.schedparam.sched_priority 537 | return 0 538 | 539 | # Set the scheduling priority for TARGET_THREAD. 540 | cdef public int pthread_setschedprio(pthread_t target_thread, int prio): 541 | key = target_thread 542 | try: 543 | g = greenlets[key] 544 | except KeyError: 545 | return libc.errno.ESRCH 546 | try: 547 | t = g.args[0] 548 | except TypeError: 549 | return libc.errno.ESRCH 550 | t.schedparam.sched_priority = prio 551 | return 0 552 | 553 | # Get thread name visible in the kernel and its interfaces. 554 | cdef public int pthread_getname_np \ 555 | ( 556 | pthread_t target_thread, 557 | char *buf, 558 | size_t buflen 559 | ): 560 | key = target_thread 561 | try: 562 | g = greenlets[key] 563 | except KeyError: 564 | return libc.errno.ESRCH 565 | try: 566 | t = g.args[0] 567 | except TypeError: 568 | return libc.errno.ESRCH 569 | if len(t.name) > buflen: 570 | return libc.errno.ERANGE 571 | name = t.name 572 | return 0 573 | 574 | # Set thread name visible in the kernel and its interfaces. 575 | cdef public int pthread_setname_np \ 576 | ( 577 | pthread_t target_thread, 578 | const char *name 579 | ): 580 | key = target_thread 581 | try: 582 | g = greenlets[key] 583 | except KeyError: 584 | return libc.errno.ESRCH 585 | try: 586 | t = g.args[0] 587 | except TypeError: 588 | return libc.errno.ESRCH 589 | t.name = name 590 | return 0 591 | 592 | # Determine level of concurrency. 593 | cdef public int pthread_getconcurrency(): 594 | return __concurrency_level 595 | 596 | # Set new concurrency level to LEVEL. 597 | cdef public int pthread_setconcurrency(int level): 598 | if level < 0: 599 | return libc.errno.EINVAL 600 | global __concurrency_level 601 | __concurrency_level = level 602 | return 0 603 | 604 | # Yield the processor to another thread or process. 605 | # This function is similar to the POSIX `sched_yield' function but 606 | # might be differently implemented in the case of a m-on-n thread 607 | # implementation. 608 | cdef public int pthread_yield(): 609 | gevent.idle() 610 | return 0 611 | 612 | # XXX 613 | # 614 | # Limit specified thread TH to run only on the processors represented 615 | # in CPUSET. 616 | cdef public int pthread_setaffinity_np \ 617 | ( 618 | pthread_t th, 619 | size_t cpusetsize, 620 | const cpu_set_t *cpuset 621 | ): 622 | return libc.errno.ENOSYS 623 | 624 | # XXX 625 | # 626 | # Get bit set in CPUSET representing the processors TH can run on. 627 | cdef public int pthread_getaffinity_np \ 628 | ( 629 | pthread_t th, 630 | size_t cpusetsize, 631 | cpu_set_t *cpuset 632 | ): 633 | return libc.errno.ENOSYS 634 | 635 | ########################################################################### 636 | # Functions for handling initialization. # 637 | ########################################################################### 638 | 639 | # Guarantee that the initialization function INIT_ROUTINE will be called 640 | # only once, even if pthread_once is executed several times with the 641 | # same ONCE_CONTROL argument. ONCE_CONTROL must point to a static or 642 | # extern variable initialized to PTHREAD_ONCE_INIT. 643 | # 644 | # The initialization functions might throw exception which is why 645 | # this function is not marked with __THROW. 646 | cdef public int pthread_once \ 647 | ( 648 | pthread_once_t *once_control, 649 | void (*init_routine) () 650 | ): 651 | if PTHREAD_ONCE_INIT == once_control[0]: 652 | once_control[0] = ONCE_DONE 653 | init_routine() 654 | return 0 655 | else: 656 | return 0 657 | 658 | ########################################################################### 659 | # Functions for handling cancellation. # 660 | # 661 | # Note that these functions are explicitly not marked to not throw an # 662 | # exception in C++ code. If cancellation is implemented by unwinding # 663 | # this is necessary to have the compiler generate the unwind information. # 664 | ########################################################################### 665 | 666 | # Set cancelability state of current thread to STATE, returning old 667 | # state in *OLDSTATE if OLDSTATE is not NULL. 668 | cdef public int pthread_setcancelstate(int state, int *oldstate): 669 | g = gevent.getcurrent() 670 | key = g 671 | if key not in greenlets: 672 | return libc.errno.ESRCH 673 | try: 674 | t = g.args[0] 675 | except TypeError: 676 | return libc.errno.ESRCH 677 | oldstate[0] = t.cancelstate 678 | t.cancelstate = state 679 | return 0 680 | 681 | # Set cancellation state of current thread to TYPE, returning the old 682 | # type in *OLDTYPE if OLDTYPE is not NULL. 683 | cdef public int pthread_setcanceltype(int type_, int *oldtype): 684 | g = gevent.getcurrent() 685 | key = g 686 | try: 687 | t = g.args[0] 688 | except TypeError: 689 | return libc.errno.ESRCH 690 | oldtype[0] = t.canceltype 691 | t.canceltype = type_ 692 | return 0 693 | 694 | # Cancel THREAD immediately or at the next possibility. 695 | cdef public int pthread_cancel(pthread_t th): 696 | key = th 697 | try: 698 | g = greenlets[key] 699 | except KeyError: 700 | return libc.errno.ESRCH 701 | try: 702 | t = g.args[0] 703 | except TypeError: 704 | return libc.errno.ESRCH 705 | t.cancelstate = PTHREAD_CANCEL_ENABLE 706 | del t 707 | del g 708 | del key 709 | __cancel(th, PTHREAD_CANCELED) 710 | return 0 711 | 712 | # Test for pending cancellation for the current thread and terminate 713 | # the thread as per pthread_exit(PTHREAD_CANCELED) if it has been 714 | # cancelled. 715 | cdef public void pthread_testcancel(): 716 | g = gevent.getcurrent() 717 | key = g 718 | if key not in greenlets: 719 | return 720 | cdef pthread_t th = g 721 | try: 722 | t = g.args[0] 723 | except TypeError: 724 | return 725 | if PTHREAD_CANCEL_ENABLE != t.cancelstate: 726 | return 727 | del t 728 | del key 729 | del g 730 | __cancel(th, PTHREAD_CANCELED) 731 | 732 | # XXX 733 | cdef public int pthread_kill(pthread_t th, int sig): 734 | key = th 735 | try: 736 | g = greenlets[key] 737 | except KeyError: 738 | return libc.errno.ESRCH 739 | return libc.errno.ENOSYS 740 | 741 | ########################################################################### 742 | # Mutex handling. # 743 | ########################################################################### 744 | 745 | cdef class MutexAttr: 746 | 747 | cdef int pshared 748 | cdef int kind 749 | cdef int protocol 750 | cdef int prioceiling 751 | cdef int robustness 752 | 753 | cdef int init(self, const pthread_mutexattr_t *attr): 754 | if NULL == attr: 755 | return self.set_default() 756 | else: 757 | return self.set(attr) 758 | 759 | cdef int set_default(self): 760 | cdef pthread_mutexattr_t attr 761 | cdef int fail 762 | fail = pthread_mutexattr_init(&attr) 763 | if fail: 764 | return fail 765 | return self.set(&attr) 766 | 767 | cdef int set(self, const pthread_mutexattr_t *attr): 768 | cdef int fail = pthread_mutexattr_getpshared(attr, &self.pshared) 769 | if fail: 770 | return fail 771 | fail = pthread_mutexattr_gettype(attr, &self.kind) 772 | if fail: 773 | return fail 774 | fail = pthread_mutexattr_getprotocol(attr, &self.protocol) 775 | if fail: 776 | return fail 777 | fail = \ 778 | pthread_mutexattr_getprioceiling( 779 | attr, 780 | &self.prioceiling 781 | ) 782 | if fail: 783 | return fail 784 | fail = pthread_mutexattr_getrobust(attr, &self.robustness) 785 | if fail: 786 | return fail 787 | return 0 788 | 789 | cdef int get(self, pthread_mutexattr_t *attr): 790 | cdef int fail = pthread_mutexattr_setpshared(attr, self.pshared) 791 | if fail: 792 | return fail 793 | fail = pthread_mutexattr_settype(attr, self.kind) 794 | if fail: 795 | return fail 796 | fail = pthread_mutexattr_setprotocol(attr, self.protocol) 797 | if fail: 798 | return fail 799 | fail = pthread_mutexattr_setprioceiling(attr, self.prioceiling) 800 | if fail: 801 | return fail 802 | fail = pthread_mutexattr_setrobust(attr, self.robustness) 803 | if fail: 804 | return fail 805 | return 0 806 | 807 | cdef class Mutex: 808 | 809 | cdef MutexAttr attr 810 | cdef object _block 811 | cdef object _owner 812 | cdef object _count 813 | cdef object __weakref__ 814 | 815 | def __init__(self): 816 | self._block = gevent.lock.Semaphore(1) 817 | self._owner = None 818 | self._count = 0 819 | 820 | cdef int acquire(self, blocking, timeout): 821 | if self._owner is None: 822 | owner = None 823 | else: 824 | owner = self._owner() 825 | if owner is None or owner.ready(): 826 | return EOWNERDEAD 827 | me = gevent.getcurrent() 828 | if owner is me: 829 | if self.attr.kind == PTHREAD_MUTEX_RECURSIVE_NP: 830 | self._count = self._count + 1 831 | return 0 832 | elif self.attr.kind == PTHREAD_MUTEX_ERRORCHECK_NP: 833 | return EDEADLK 834 | rc = self._block.acquire(blocking, timeout) 835 | if rc: 836 | self._owner = weakref.ref(me) 837 | self._count = 1 838 | return 0 839 | else: 840 | if timeout is None: 841 | return libc.errno.EBUSY 842 | else: 843 | return libc.errno.ETIMEDOUT 844 | 845 | cdef int release(self): 846 | if self._owner is None: 847 | owner = None 848 | else: 849 | owner = self._owner() 850 | me = gevent.getcurrent() 851 | attr = self.attr 852 | if owner is not me and \ 853 | ( 854 | attr.kind == PTHREAD_MUTEX_ERRORCHECK or \ 855 | attr.kind == PTHREAD_MUTEX_RECURSIVE or \ 856 | attr.robustness 857 | ): 858 | return libc.errno.EPERM 859 | count = self._count - 1 860 | self._count = count 861 | if not count: 862 | self._owner = None 863 | self._block.release() 864 | return 0 865 | 866 | cdef int cond_wait_check(self): 867 | if PTHREAD_MUTEX_ERRORCHECK == self.attr.kind or \ 868 | self.attr.robustness: 869 | if self._owner is None: 870 | return EOWNERDEAD 871 | else: 872 | owner = self._owner() 873 | if owner is None: 874 | return EOWNERDEAD 875 | me = gevent.getcurrent() 876 | if owner is not me: 877 | return libc.errno.EPERM 878 | return 0 879 | 880 | # Initialize a mutex. 881 | cdef public int pthread_mutex_init \ 882 | ( 883 | pthread_mutex_t *mutex, 884 | const pthread_mutexattr_t *mutexattr 885 | ): 886 | if not C10kPthread_initialized: 887 | (mutex)[0] = 0 888 | return 0 889 | pAttr = MutexAttr() 890 | cdef int fail = pAttr.init(mutexattr) 891 | if fail: 892 | return fail 893 | pMutex = Mutex() 894 | pMutex.attr = pAttr 895 | key = \ 896 | \ 897 | \ 898 | pMutex 899 | mutexes[key] = pMutex 900 | (mutex)[0] = \ 901 | \ 902 | pMutex 903 | return 0 904 | 905 | # Destroy a mutex. 906 | cdef public int pthread_mutex_destroy(pthread_mutex_t *mutex): 907 | if 0 == (mutex)[0]: 908 | return 0 909 | key = (mutex)[0] 910 | try: 911 | del mutexes[key] 912 | except KeyError: 913 | return libc.errno.ESRCH 914 | else: 915 | return 0 916 | 917 | # Try locking a mutex. 918 | cdef public int pthread_mutex_trylock(pthread_mutex_t *mutex): 919 | key = (mutex)[0] 920 | try: 921 | pMutex = mutexes[key] 922 | except KeyError: 923 | return libc.errno.ESRCH 924 | return pMutex.acquire(False, None) 925 | 926 | # Lock a mutex. 927 | cdef public int pthread_mutex_lock(pthread_mutex_t *mutex): 928 | if 0 == (mutex)[0]: 929 | return 0 930 | key = (mutex)[0] 931 | try: 932 | pMutex = mutexes[key] 933 | except KeyError: 934 | return libc.errno.ESRCH 935 | return pMutex.acquire(True, None) 936 | 937 | # Wait until lock becomes available, or specified time passes. 938 | cdef public int pthread_mutex_timedlock \ 939 | ( 940 | pthread_mutex_t *mutex, 941 | const posix.time.timespec *abstime 942 | ): 943 | key = (mutex)[0] 944 | try: 945 | pMutex = mutexes[key] 946 | except KeyError: 947 | return libc.errno.ESRCH 948 | return \ 949 | pMutex.acquire( 950 | True, 951 | max(abstime.tv_sec-int(time.time()), 0) 952 | ) 953 | 954 | # Unlock a mutex. 955 | cdef public int pthread_mutex_unlock(pthread_mutex_t *mutex): 956 | if 0 == (mutex)[0]: 957 | return 0 958 | key = (mutex)[0] 959 | try: 960 | pMutex = mutexes[key] 961 | except KeyError: 962 | return libc.errno.ESRCH 963 | return pMutex.release() 964 | 965 | # Get the priority ceiling of MUTEX. 966 | cdef public int pthread_mutex_getprioceiling \ 967 | ( 968 | const pthread_mutex_t *mutex, 969 | int *prioceiling 970 | ): 971 | key = (mutex)[0] 972 | try: 973 | pMutex = mutexes[key] 974 | except KeyError: 975 | return libc.errno.ESRCH 976 | prioceiling[0] = pMutex.attr.prioceiling 977 | 978 | # XXX 979 | # 980 | # Set the priority ceiling of MUTEX to PRIOCEILING, return old 981 | # priority ceiling value in *OLD_CEILING. 982 | cdef public int pthread_mutex_setprioceiling \ 983 | ( 984 | pthread_mutex_t *mutex, 985 | int prioceiling, 986 | int *old_ceiling 987 | ): 988 | key = (mutex)[0] 989 | try: 990 | pMutex = mutexes[key] 991 | except KeyError: 992 | return libc.errno.ESRCH 993 | g = gevent.getcurrent() 994 | key = g 995 | try: 996 | g = greenlets[key] 997 | except KeyError: 998 | return libc.errno.ESRCH 999 | try: 1000 | t = g.args[0] 1001 | except TypeError: 1002 | return libc.errno.ESRCH 1003 | attr = pMutex.attr 1004 | if attr.protocol == PTHREAD_PRIO_NONE: 1005 | return libc.errno.EINVAL 1006 | elif attr.protocol == PTHREAD_PRIO_PROTECT and \ 1007 | t.schedparam.sched_priority > attr.prioceiling: 1008 | return libc.errno.EINVAL 1009 | cdef int fail = pMutex.acquire(True, None) 1010 | if fail: 1011 | return fail 1012 | old_ceiling[0] = pMutex.attr.prioceiling 1013 | pMutex.attr.prioceiling = prioceiling 1014 | pMutex.release() 1015 | return 0 1016 | 1017 | # XXX 1018 | # 1019 | # Declare the state protected by MUTEX as consistent. 1020 | cdef public int pthread_mutex_consistent(pthread_mutex_t *mutex): 1021 | key = (mutex)[0] 1022 | try: 1023 | pMutex = mutexes[key] 1024 | except KeyError: 1025 | return libc.errno.ESRCH 1026 | if pMutex.attr.robustness: 1027 | return 0 1028 | else: 1029 | return libc.errno.EINVAL 1030 | 1031 | cdef public int pthread_mutex_consistent_np(pthread_mutex_t *mutex): 1032 | return pthread_mutex_consistent(mutex) 1033 | 1034 | ########################################################################### 1035 | # Functions for handling read-write locks. # 1036 | ########################################################################### 1037 | 1038 | cdef class RwlockAttr: 1039 | 1040 | cdef int pshared 1041 | cdef int pref 1042 | 1043 | cdef int init(self, const pthread_rwlockattr_t *attr): 1044 | if NULL == attr: 1045 | return self.set_default() 1046 | else: 1047 | return self.set(attr) 1048 | 1049 | cdef int set_default(self): 1050 | cdef pthread_rwlockattr_t attr 1051 | cdef int fail = pthread_rwlockattr_init(&attr) 1052 | if fail: 1053 | return fail 1054 | return self.set(&attr) 1055 | 1056 | cdef int set(self, const pthread_rwlockattr_t *attr): 1057 | cdef int fail = pthread_rwlockattr_getpshared(attr, &self.pshared) 1058 | if fail: 1059 | return fail 1060 | fail = pthread_rwlockattr_getkind_np(attr, &self.pref) 1061 | if fail: 1062 | return fail 1063 | return 0 1064 | 1065 | cdef int get(self, pthread_rwlockattr_t *attr): 1066 | cdef int fail = pthread_rwlockattr_setpshared(attr, self.pshared) 1067 | if fail: 1068 | return fail 1069 | fail = pthread_rwlockattr_setkind_np(attr, self.pref) 1070 | if fail: 1071 | return fail 1072 | return 0 1073 | 1074 | cdef class Rwlock_PREFER_READER: 1075 | 1076 | cdef RwlockAttr attr 1077 | cdef int balance 1078 | cdef object _block 1079 | cdef object _ready 1080 | cdef dict _owner 1081 | cdef object __weakref__ 1082 | 1083 | def __init__(self): 1084 | self.balance = 0 1085 | self._block = gevent.lock.Semaphore(1) 1086 | self._ready = gevent.event.Event() 1087 | self._owner = {} 1088 | 1089 | cdef int rd_acquire(self, blocking=True, timeout=None): 1090 | g = gevent.getcurrent() 1091 | key = g 1092 | if key in self._owner: 1093 | return EDEADLK 1094 | if self.balance > 0: 1095 | self.balance += 1 1096 | self._owner[key] = 0 1097 | return 0 1098 | elif 0 == self.balance: 1099 | self.balance = -1 1100 | rc = self._block.acquire(blocking, timeout) 1101 | if rc: 1102 | self.balance = abs(self.balance) 1103 | self._ready.set() 1104 | self._owner[key] = 0 1105 | return 0 1106 | else: 1107 | if timeout is None: 1108 | return libc.errno.EBUSY 1109 | else: 1110 | return libc.errno.ETIMEDOUT 1111 | else: 1112 | self.balance -= 1 1113 | rc = self._ready.wait(timeout) 1114 | if rc: 1115 | self._owner[key] = 0 1116 | return 0 1117 | else: 1118 | return libc.errno.ETIMEDOUT 1119 | 1120 | cdef int wr_acquire(self, blocking, timeout): 1121 | g = gevent.getcurrent() 1122 | key = g 1123 | if key in self._owner: 1124 | return EDEADLK 1125 | rc = self._block.acquire(blocking, timeout) 1126 | if rc: 1127 | self._owner[key] = 1 1128 | return 0 1129 | else: 1130 | if timeout is None: 1131 | return libc.errno.EBUSY 1132 | else: 1133 | return libc.errno.ETIMEDOUT 1134 | 1135 | cdef int release(self): 1136 | g = gevent.getcurrent() 1137 | key = g 1138 | is_writer = self._owner.get(key) 1139 | if key is None: 1140 | return libc.errno.EPERM 1141 | if key: 1142 | self._block.release() 1143 | del self._owner[key] 1144 | return 0 1145 | else: 1146 | self.balance -= 1 1147 | if 0 == self.balance: 1148 | self._ready.clear() 1149 | self._block.release() 1150 | del self._owner[key] 1151 | return 0 1152 | 1153 | # Initialize read-write lock RWLOCK using attributes ATTR, or use 1154 | # the default values if later is NULL. 1155 | cdef public int pthread_rwlock_init \ 1156 | ( 1157 | pthread_rwlock_t *rwlock, 1158 | const pthread_rwlockattr_t *attr 1159 | ): 1160 | pAttr = RwlockAttr() 1161 | cdef int fail = pAttr.init(attr) 1162 | if fail: 1163 | return fail 1164 | pRwlock = Rwlock_PREFER_READER() 1165 | pRwlock.attr = pAttr 1166 | key = \ 1167 | \ 1168 | \ 1169 | pRwlock 1170 | rwlocks[key] = pRwlock 1171 | (rwlock)[0] = \ 1172 | \ 1173 | pRwlock 1174 | return 0 1175 | 1176 | # Destroy read-write lock RWLOCK. 1177 | cdef public int pthread_rwlock_destroy(pthread_rwlock_t *rwlock): 1178 | key = (rwlock)[0] 1179 | try: 1180 | del rwlocks[key] 1181 | except KeyError: 1182 | return libc.errno.ESRCH 1183 | else: 1184 | return 0 1185 | 1186 | # Acquire read lock for RWLOCK. 1187 | cdef public int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock): 1188 | key = (rwlock)[0] 1189 | try: 1190 | pRwlock = rwlocks[key] 1191 | except KeyError: 1192 | return libc.errno.ESRCH 1193 | return pRwlock.rd_acquire(True, None) 1194 | 1195 | # Try to acquire read lock for RWLOCK. 1196 | cdef public int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock): 1197 | key = (rwlock)[0] 1198 | try: 1199 | pRwlock = rwlocks[key] 1200 | except KeyError: 1201 | return libc.errno.ESRCH 1202 | return pRwlock.rd_acquire(False, None) 1203 | 1204 | # Try to acquire read lock for RWLOCK or return after specfied time. 1205 | cdef public int pthread_rwlock_timedrdlock \ 1206 | ( 1207 | pthread_rwlock_t *rwlock, 1208 | const posix.time.timespec *abstime 1209 | ): 1210 | key = (rwlock)[0] 1211 | try: 1212 | pRwlock = rwlocks[key] 1213 | except KeyError: 1214 | return libc.errno.ESRCH 1215 | return \ 1216 | pRwlock.rd_acquire( 1217 | True, 1218 | max(abstime.tv_sec-int(time.time()), 0) 1219 | ) 1220 | 1221 | # Acquire write lock for RWLOCK. 1222 | cdef public int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock): 1223 | key = (rwlock)[0] 1224 | try: 1225 | pRwlock = rwlocks[key] 1226 | except KeyError: 1227 | return libc.errno.ESRCH 1228 | return pRwlock.wr_acquire(True, None) 1229 | 1230 | # Try to acquire write lock for RWLOCK. 1231 | cdef public int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock): 1232 | key = (rwlock)[0] 1233 | try: 1234 | pRwlock = rwlocks[key] 1235 | except KeyError: 1236 | return libc.errno.ESRCH 1237 | return pRwlock.wr_acquire(False, None) 1238 | 1239 | # Try to acquire write lock for RWLOCK or return after specfied time. 1240 | cdef public int pthread_rwlock_timedwrlock \ 1241 | ( 1242 | pthread_rwlock_t *rwlock, 1243 | const posix.time.timespec *abstime 1244 | ): 1245 | key = (rwlock)[0] 1246 | try: 1247 | pRwlock = rwlocks[key] 1248 | except KeyError: 1249 | return libc.errno.ESRCH 1250 | return \ 1251 | pRwlock.wr_acquire( 1252 | True, 1253 | max(abstime.tv_sec-int(time.time()), 0) 1254 | ) 1255 | 1256 | # Unlock RWLOCK. 1257 | cdef public int pthread_rwlock_unlock(pthread_rwlock_t *rwlock): 1258 | key = (rwlock)[0] 1259 | try: 1260 | pRwlock = rwlocks[key] 1261 | except KeyError: 1262 | return libc.errno.ESRCH 1263 | return pRwlock.release() 1264 | 1265 | ########################################################################### 1266 | # Functions for handling conditional variables. # 1267 | ########################################################################### 1268 | 1269 | cdef class CondAttr: 1270 | 1271 | cdef int pshared 1272 | cdef __clockid_t clock_id 1273 | 1274 | cdef int init(self, const pthread_condattr_t *attr): 1275 | if NULL == attr: 1276 | return self.set_default() 1277 | else: 1278 | return self.set(attr) 1279 | 1280 | cdef int set_default(self): 1281 | cdef pthread_condattr_t attr 1282 | cdef int fail = pthread_condattr_init(&attr) 1283 | if fail: 1284 | return fail 1285 | return self.set(&attr) 1286 | 1287 | cdef int set(self, const pthread_condattr_t *attr): 1288 | cdef int fail = pthread_condattr_getpshared(attr, &self.pshared) 1289 | if fail: 1290 | return fail 1291 | fail = pthread_condattr_getclock(attr, &self.clock_id) 1292 | if fail != 0: 1293 | return fail 1294 | return 0 1295 | 1296 | cdef int get(self, pthread_condattr_t *attr): 1297 | cdef int fail = pthread_condattr_setpshared(attr, self.pshared) 1298 | if fail: 1299 | return fail 1300 | fail = pthread_condattr_setclock(attr, self.clock_id) 1301 | if fail: 1302 | return fail 1303 | return 0 1304 | 1305 | cdef class Cond: 1306 | 1307 | cdef CondAttr attr 1308 | cdef public object queue 1309 | 1310 | def __init__(self): 1311 | self.queue = gevent.queue.Queue() 1312 | 1313 | cdef int init(self, CondAttr attr): 1314 | self.attr = attr 1315 | return 0 1316 | 1317 | # Initialize condition variable COND using attributes ATTR, or use 1318 | # the default values if later is NULL. 1319 | cdef public int pthread_cond_init \ 1320 | ( 1321 | pthread_cond_t *cond, 1322 | const pthread_condattr_t *cond_attr 1323 | ): 1324 | if not C10kPthread_initialized: 1325 | (cond)[0] = 0 1326 | return 0 1327 | pAttr = CondAttr() 1328 | cdef int fail = pAttr.init(cond_attr) 1329 | if fail: 1330 | return fail 1331 | pCond = Cond() 1332 | pCond.attr = pAttr 1333 | key = \ 1334 | \ 1335 | \ 1336 | pCond 1337 | conds[key] = pCond 1338 | (cond)[0] = \ 1339 | \ 1340 | pCond 1341 | return 0 1342 | 1343 | # Destroy condition variable COND. 1344 | cdef public int pthread_cond_destroy(pthread_cond_t *cond): 1345 | key = (cond)[0] 1346 | try: 1347 | del conds[key] 1348 | except KeyError: 1349 | return libc.errno.ESRCH 1350 | else: 1351 | return 0 1352 | 1353 | # Wake up one thread waiting for condition variable COND. 1354 | cdef public int pthread_cond_signal(pthread_cond_t *cond): 1355 | if 0 == (cond)[0]: 1356 | return 0 1357 | key = (cond)[0] 1358 | try: 1359 | pCond = conds[key] 1360 | except KeyError: 1361 | return libc.errno.ESRCH 1362 | queue = pCond.queue 1363 | if len(queue.getters) > 0: 1364 | queue.put(None) 1365 | return 0 1366 | else: 1367 | return 0 1368 | 1369 | # Wake up all threads waiting for condition variables COND. 1370 | cdef public int pthread_cond_broadcast(pthread_cond_t *cond): 1371 | key = (cond)[0] 1372 | try: 1373 | pCond = conds[key] 1374 | except KeyError: 1375 | return libc.errno.ESRCH 1376 | queue = pCond.queue 1377 | if len(queue.getters) > 0: 1378 | pCond.queue = gevent.queue.Queue() 1379 | while len(queue.getters) > 0: 1380 | queue.put(None) 1381 | return 0 1382 | else: 1383 | return 0 1384 | 1385 | # Wait for condition variable COND to be signaled or broadcast. 1386 | # MUTEX is assumed to be locked before. 1387 | # 1388 | # This function is a cancellation point and therefore not marked with 1389 | # __THROW. 1390 | cdef public int pthread_cond_wait \ 1391 | ( 1392 | pthread_cond_t *cond, 1393 | pthread_mutex_t *mutex 1394 | ): 1395 | if 0 == (cond)[0]: 1396 | return 0 1397 | key = (mutex)[0] 1398 | try: 1399 | pMutex = mutexes[key] 1400 | except KeyError: 1401 | return libc.errno.ESRCH 1402 | fail = pMutex.cond_wait_check() 1403 | if fail: 1404 | return fail 1405 | key = (cond)[0] 1406 | try: 1407 | pCond = conds[key] 1408 | except KeyError: 1409 | return libc.errno.ESRCH 1410 | pCond.queue.get(block=True) 1411 | return 0 1412 | 1413 | # Wait for condition variable COND to be signaled or broadcast until 1414 | # ABSTIME. MUTEX is assumed to be locked before. ABSTIME is an 1415 | # absolute time specification; zero is the beginning of the epoch 1416 | # (00:00:00 GMT, January 1, 1970). 1417 | # 1418 | # This function is a cancellation point and therefore not marked with 1419 | # __THROW. 1420 | cdef public int pthread_cond_timedwait \ 1421 | ( 1422 | pthread_cond_t *cond, 1423 | pthread_mutex_t *mutex, 1424 | const posix.time.timespec *abstime 1425 | ): 1426 | key = (mutex)[0] 1427 | try: 1428 | pMutex = mutexes[key] 1429 | except KeyError: 1430 | return libc.errno.ESRCH 1431 | fail = pMutex.cond_wait_check() 1432 | if fail: 1433 | return fail 1434 | key = (cond)[0] 1435 | try: 1436 | pCond = conds[key] 1437 | except KeyError: 1438 | return libc.errno.ESRCH 1439 | pCond.queue.get( 1440 | block=True, 1441 | timeout=max(abstime.tv_sec-int(time.time()), 0) 1442 | ) 1443 | return 0 1444 | 1445 | ########################################################################### 1446 | # Functions to handle spinlocks. # 1447 | ########################################################################### 1448 | 1449 | # Initialize the spinlock LOCK. If PSHARED is nonzero the spinlock can 1450 | # be shared between different processes. 1451 | cdef public int pthread_spin_init(pthread_spinlock_t *lock, int pshared): 1452 | pAttr = MutexAttr() 1453 | cdef int fail = pAttr.init(NULL) 1454 | pAttr.pshared = pshared 1455 | if fail: 1456 | return fail 1457 | pMutex = Mutex() 1458 | pMutex.attr = pAttr 1459 | key = \ 1460 | \ 1461 | \ 1462 | pMutex 1463 | mutexes[key] = pMutex 1464 | (lock)[0] = \ 1465 | \ 1466 | pMutex 1467 | return 0 1468 | 1469 | # Destroy the spinlock LOCK. 1470 | cdef public int pthread_spin_destroy(pthread_spinlock_t *lock): 1471 | key = (lock)[0] 1472 | try: 1473 | del mutexes[key] 1474 | except KeyError: 1475 | return libc.errno.ESRCH 1476 | else: 1477 | return 0 1478 | 1479 | # Wait until spinlock LOCK is retrieved. 1480 | cdef public int pthread_spin_lock(pthread_spinlock_t *lock): 1481 | if 0 == (lock)[0]: 1482 | return 0 1483 | key = (lock)[0] 1484 | try: 1485 | pMutex = mutexes[key] 1486 | except KeyError: 1487 | return libc.errno.ESRCH 1488 | cdef int rc = pMutex.acquire(False, None) 1489 | while libc.errno.EBUSY == rc: 1490 | rc = pMutex.acquire(False, None) 1491 | return rc 1492 | 1493 | # Try to lock spinlock LOCK. 1494 | cdef public int pthread_spin_trylock(pthread_spinlock_t *lock): 1495 | key = (lock)[0] 1496 | try: 1497 | pMutex = mutexes[key] 1498 | except KeyError: 1499 | return libc.errno.ESRCH 1500 | return pMutex.acquire(False, None) 1501 | 1502 | # Release spinlock LOCK. 1503 | cdef public int pthread_spin_unlock(pthread_spinlock_t *lock): 1504 | key = (lock)[0] 1505 | try: 1506 | pMutex = mutexes[key] 1507 | except KeyError: 1508 | return libc.errno.ESRCH 1509 | return pMutex.release() 1510 | 1511 | ########################################################################### 1512 | # Functions to handle barriers. # 1513 | ########################################################################### 1514 | 1515 | cdef class BarrierAttr: 1516 | 1517 | cdef int pshared 1518 | 1519 | cdef int init(self, const pthread_barrierattr_t *attr): 1520 | if NULL == attr: 1521 | return self.set_default() 1522 | else: 1523 | return self.set(attr) 1524 | 1525 | cdef int set_default(self): 1526 | cdef pthread_barrierattr_t attr 1527 | cdef int fail = pthread_barrierattr_init(&attr) 1528 | if fail: 1529 | return fail 1530 | return self.set(&attr) 1531 | 1532 | cdef int set(self, const pthread_barrierattr_t *attr): 1533 | return pthread_barrierattr_getpshared(attr, &self.pshared) 1534 | 1535 | cdef int get(self, pthread_barrierattr_t *attr): 1536 | return pthread_barrierattr_setpshared(attr, self.pshared) 1537 | 1538 | cdef class Barrier: 1539 | 1540 | cdef BarrierAttr attr 1541 | cdef int count 1542 | cdef int waiters 1543 | cdef object ready 1544 | 1545 | cdef int init(self, BarrierAttr attr): 1546 | self.attr = attr 1547 | return 0 1548 | 1549 | # Initialize BARRIER with the attributes in ATTR. The barrier is 1550 | # opened when COUNT waiters arrived. 1551 | cdef public int pthread_barrier_init \ 1552 | ( 1553 | pthread_barrier_t *barrier, 1554 | const pthread_barrierattr_t *attr, 1555 | unsigned int count 1556 | ): 1557 | pAttr = BarrierAttr() 1558 | cdef int fail = pAttr.init(attr) 1559 | if fail: 1560 | return fail 1561 | pBarrier = Barrier() 1562 | pBarrier.attr = pAttr 1563 | pBarrier.count = count 1564 | pBarrier.waiters = 0 1565 | pBarrier.ready = gevent.event.Event() 1566 | key = \ 1567 | \ 1568 | \ 1569 | pBarrier 1570 | barriers[key] = pBarrier 1571 | (barrier)[0] = \ 1572 | \ 1573 | pBarrier 1574 | return 0 1575 | 1576 | # Destroy a previously dynamically initialized barrier BARRIER. 1577 | cdef public int pthread_barrier_destroy(pthread_barrier_t *barrier): 1578 | key = (barrier)[0] 1579 | try: 1580 | del barriers[key] 1581 | except KeyError: 1582 | return libc.errno.ESRCH 1583 | else: 1584 | return 0 1585 | 1586 | # Wait on barrier BARRIER. 1587 | cdef public int pthread_barrier_wait(pthread_barrier_t *barrier): 1588 | key = (barrier)[0] 1589 | try: 1590 | pBarrier = barriers[key] 1591 | except KeyError: 1592 | return libc.errno.ESRCH 1593 | cdef waiters = pBarrier.waiters + 1 1594 | if waiters >= pBarrier.count: 1595 | pBarrier.waiters = 0 1596 | pBarrier.ready.set() 1597 | return 0 1598 | else: 1599 | pBarrier.waiters = waiters 1600 | pBarrier.ready.wait() 1601 | return 0 1602 | 1603 | ########################################################################### 1604 | # Functions for handling thread-specific data. # 1605 | ########################################################################### 1606 | 1607 | cdef class Key: 1608 | 1609 | cdef void *specific 1610 | cdef (void (*) (void *) nogil) destr_function 1611 | 1612 | def __dealloc__(self): 1613 | if self.specific != NULL and self.destr_function != NULL: 1614 | self.destr_function(self.specific) 1615 | 1616 | # Create a key value identifying a location in the thread-specific 1617 | # data area. Each thread maintains a distinct thread-specific data 1618 | # area. DESTR_FUNCTION, if non-NULL, is called with the value 1619 | # associated to that key when the key is destroyed. 1620 | # DESTR_FUNCTION is not called if the value associated is NULL when 1621 | # the key is destroyed. 1622 | cdef public int pthread_key_create \ 1623 | ( 1624 | pthread_key_t *key, 1625 | void (*destr_function) (void *) nogil 1626 | ): 1627 | global __key_limbo_specific 1628 | if not C10kPthread_initialized: 1629 | __key_limbo_specific = NULL 1630 | key[0] = __key_limbo 1631 | return 0 1632 | if LOCAL_KEY not in __local.__dict__: 1633 | __local.__dict__[LOCAL_KEY] = {} 1634 | pKey = Key() 1635 | pKey.specific = NULL 1636 | pKey.destr_function = destr_function 1637 | id_ = \ 1638 | \ 1639 | \ 1640 | pKey 1641 | __local.__dict__[LOCAL_KEY][id_] = pKey 1642 | key[0] = \ 1643 | \ 1644 | \ 1645 | pKey 1646 | return 0 1647 | 1648 | # Destroy KEY. 1649 | cdef public int pthread_key_delete(pthread_key_t key): 1650 | if LOCAL_KEY not in __local.__dict__: 1651 | return libc.errno.ESRCH 1652 | id_ = key 1653 | try: 1654 | del __local.__dict__[id_] 1655 | except KeyError: 1656 | return libc.errno.ESRCH 1657 | return 0 1658 | 1659 | # Return current value of the thread-specific data slot identified by KEY. 1660 | cdef public void *pthread_getspecific(pthread_key_t key): 1661 | if key == __key_limbo: 1662 | return __key_limbo_specific 1663 | if LOCAL_KEY not in __local.__dict__: 1664 | return NULL 1665 | id_ = key 1666 | try: 1667 | pKey = __local.__dict__[id_] 1668 | except KeyError: 1669 | return NULL 1670 | return pKey.specific 1671 | 1672 | # Store POINTER in the thread-specific data slot identified by KEY. 1673 | cdef public int pthread_setspecific \ 1674 | ( 1675 | pthread_key_t key, 1676 | const void *pointer 1677 | ): 1678 | global __key_limbo_specific 1679 | if key == __key_limbo: 1680 | __key_limbo_specific = pointer 1681 | return 0 1682 | if LOCAL_KEY not in __local.__dict__: 1683 | return libc.errno.ESRCH 1684 | id_ = key 1685 | try: 1686 | pKey = __local.__dict__[id_] 1687 | except KeyError: 1688 | return libc.errno.ESRCH 1689 | pKey.specific = pointer 1690 | return 0 1691 | 1692 | ########################################################################### 1693 | # Install handlers to be called when a new process is created with FORK. # 1694 | # The PREPARE handler is called in the parent process just before # 1695 | # performing FORK. The PARENT handler is called in the parent process # 1696 | # just after FORK. # 1697 | # The CHILD handler is called in the child process. Each of the three # 1698 | # handlers can be NULL, meaning that no handler needs to be called at # 1699 | # that point. # 1700 | # PTHREAD_ATFORK can be called several times, in which case the PREPARE # 1701 | # handlers are called in LIFO order (last added with PTHREAD_ATFORK, # 1702 | # first called before FORK), and the PARENT and CHILD handlers are called # 1703 | # in FIFO (first added, first called). # 1704 | ########################################################################### 1705 | 1706 | cdef public int pthread_atfork \ 1707 | ( 1708 | void (*prepare) (), 1709 | void (*parent) (), 1710 | void (*child) () 1711 | ): 1712 | if prepare != NULL: 1713 | try: 1714 | capsule = cpython.pycapsule.PyCapsule_New( 1715 | prepare, 1716 | NULL, 1717 | NULL 1718 | ) 1719 | except MemoryError: 1720 | return libc.errno.ENOMEM 1721 | atfork_prepare.append(capsule) 1722 | if parent != NULL: 1723 | try: 1724 | capsule = cpython.pycapsule.PyCapsule_New( 1725 | parent, 1726 | NULL, 1727 | NULL 1728 | ) 1729 | except MemoryError: 1730 | return libc.errno.ENOMEM 1731 | atfork_parent.append(capsule) 1732 | if child != NULL: 1733 | try: 1734 | capsule = cpython.pycapsule.PyCapsule_New( 1735 | child, 1736 | NULL, 1737 | NULL 1738 | ) 1739 | except MemoryError: 1740 | return libc.errno.ENOMEM 1741 | atfork_child.append(capsule) 1742 | return 0 1743 | 1744 | cdef public posix.types.pid_t fork(): 1745 | cdef (void (*) ()) cb 1746 | for capsule in reversed(atfork_prepare): 1747 | cb = \ 1748 | cpython.pycapsule.PyCapsule_GetPointer(capsule, NULL) 1749 | cb() 1750 | pid = gevent.os.fork() 1751 | if 0 == pid: 1752 | for capsule in atfork_child: 1753 | cb = \ 1754 | cpython.pycapsule.PyCapsule_GetPointer(capsule, NULL) 1755 | cb() 1756 | return 0 1757 | else: 1758 | for capsule in atfork_parent: 1759 | cb = \ 1760 | cpython.pycapsule.PyCapsule_GetPointer(capsule, NULL) 1761 | cb() 1762 | return pid 1763 | -------------------------------------------------------------------------------- /src/c10k/C10kPthread.setup: -------------------------------------------------------------------------------- 1 | import distutils.command.build_ext 2 | import distutils.core 3 | import distutils.extension 4 | import os.path 5 | import sys 6 | import sysconfig 7 | 8 | name = os.path.splitext(os.path.basename(__file__))[0] 9 | home = os.path.abspath(sys.path[0]) 10 | extra_compile_args = sysconfig.get_config_var('CFLAGS').split() 11 | extra_compile_args += ['-UCYTHON_REFNANNY'] 12 | 13 | distutils.core.setup( 14 | ext_modules=[ 15 | distutils.extension.Extension( 16 | name=name, 17 | sources=[os.path.join(home, name + '.c')], 18 | extra_compile_args=extra_compile_args 19 | ) 20 | ] 21 | ) 22 | -------------------------------------------------------------------------------- /src/c10k/C10kSocket.pyx: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # cython: language_level=3 3 | 4 | cimport libc.stdio 5 | cimport libc.stdlib 6 | cimport posix.dlfcn 7 | 8 | cdef extern from '': 9 | 10 | # If the first argument of `dlsym' or `dlvsym' is set to RTLD_NEXT 11 | # the run-time address of the symbol called NAME in the next shared 12 | # object is returned. The "next" relation is defined by the order 13 | # the shared objects were loaded. 14 | void *RTLD_NEXT # ((void *) -1l) 15 | 16 | cdef public int C10kSocket_initialized = 0 17 | 18 | cdef void* load_sym(char *symname, void *proxyfunc) nogil: 19 | cdef void *funcptr = posix.dlfcn.dlsym(RTLD_NEXT, symname) 20 | if NULL == funcptr: 21 | libc.stdio.fprintf( 22 | libc.stdio.stderr, 23 | b'Cannot load symbol \'%s\' %s', 24 | symname, 25 | posix.dlfcn.dlerror() 26 | ) 27 | libc.stdlib.exit(1) 28 | if proxyfunc == funcptr: 29 | libc.stdio.fprintf( 30 | libc.stdio.stderr, 31 | b'circular reference detected, aborting!\n' 32 | ) 33 | libc.stdlib.abort() 34 | return funcptr 35 | -------------------------------------------------------------------------------- /src/c10k/C10kSocket.setup: -------------------------------------------------------------------------------- 1 | import distutils.command.build_ext 2 | import distutils.core 3 | import distutils.extension 4 | import os.path 5 | import sys 6 | import sysconfig 7 | 8 | name = os.path.splitext(os.path.basename(__file__))[0] 9 | home = os.path.abspath(sys.path[0]) 10 | extra_compile_args = sysconfig.get_config_var('CFLAGS').split() 11 | extra_compile_args += ['-UCYTHON_REFNANNY'] 12 | 13 | distutils.core.setup( 14 | ext_modules=[ 15 | distutils.extension.Extension( 16 | name=name, 17 | sources=[os.path.join(home, name + '.c')], 18 | extra_compile_args=extra_compile_args 19 | ) 20 | ] 21 | ) 22 | -------------------------------------------------------------------------------- /src/c10k/Makefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make 2 | 3 | CYTHON := cython3 4 | PYTHON := python3 5 | 6 | define PY_CONFIG_VAR_CC 7 | import distutils.sysconfig; \ 8 | print (distutils.sysconfig.get_config_var('CC')) 9 | endef 10 | CC := $(shell $(PYTHON) -c "$(PY_CONFIG_VAR_CC)") 11 | 12 | define PY_CONFIG_VAR_PYX_EXT_SUFFIX 13 | import distutils.sysconfig; print (\ 14 | distutils.sysconfig.get_config_var('EXT_SUFFIX') or '.so') 15 | endef 16 | PYX_EXT_SUFFIX := $(shell $(PYTHON) -c "$(PY_CONFIG_VAR_PYX_EXT_SUFFIX)") 17 | 18 | define PY_CONFIG_VAR_LIB_EXT_SUFFIX 19 | import distutils.sysconfig; import os.path; print (os.path.splitext(\ 20 | distutils.sysconfig.get_config_var('EXT_SUFFIX') or '.so')[1]) 21 | endef 22 | LIB_EXT_SUFFIX := $(shell $(PYTHON) -c "$(PY_CONFIG_VAR_LIB_EXT_SUFFIX)") 23 | 24 | PYX_SOURCES := $(wildcard *.pyx) 25 | PYX_C_SOURCES := $(PYX_SOURCES:.pyx=.c) 26 | PYX_C_HEADERS := $(PYX_SOURCES:.pyx=.h) 27 | PYX_MODULES := $(PYX_SOURCES:.pyx=$(PYX_EXT_SUFFIX)) 28 | LIB_MODULES := libc10k$(LIB_EXT_SUFFIX) 29 | MODULES := $(PYX_MODULES) $(LIB_MODULES) 30 | 31 | all: $(MODULES) 32 | 33 | %$(PYX_EXT_SUFFIX): %.c %.setup 34 | $(PYTHON) $(patsubst %.c,%,$<).setup build_ext --inplace 35 | 36 | %$(LIB_EXT_SUFFIX): %.c %.setup 37 | $(PYTHON) $(patsubst %.c,%,$<).setup build_ext --inplace 38 | 39 | %.c: %.pyx 40 | $(CYTHON) --embed -I. -IIncludes $< 41 | 42 | clean: 43 | rm -rf build \ 44 | $(MODULES) \ 45 | $(PYX_C_SOURCES) \ 46 | $(PYX_C_HEADERS) \ 47 | __pycache__ 48 | find . -name '*.pyc' -exec rm {} \; 49 | find . -name '__pycache__' -exec rm -d {} \; 50 | 51 | .PRECIOUS: $(PYX_C_SOURCES) 52 | 53 | .PHONY: all clean 54 | -------------------------------------------------------------------------------- /src/c10k/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '0.0.1.dev0' 2 | -------------------------------------------------------------------------------- /src/c10k/__main__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | sys.dont_write_bytecode = True 4 | 5 | import argparse 6 | import copy 7 | import os 8 | import os.path 9 | import subprocess 10 | import sysconfig 11 | 12 | from . import __doc__ as package__doc__ 13 | from . import __version__ 14 | 15 | def main(**kwargs): 16 | program, args, parser = parse(**kwargs) 17 | sys.exit(run(program, args)) 18 | 19 | def run(program, args): 20 | bin_dir = os.path.abspath(os.path.dirname(sys.argv[0])) 21 | lib_dir = \ 22 | os.path.abspath( 23 | os.path.join( 24 | os.path.dirname(__file__), 25 | os.path.pardir 26 | ) 27 | ) 28 | pyx_ext_suffix = sysconfig.get_config_var('EXT_SUFFIX') 29 | lib_ext_suffix = os.path.splitext(pyx_ext_suffix)[1] 30 | for libpython_so in sysconfig.get_config_var('LDLIBRARY').split(): 31 | if libpython_so.startswith('libpython3.') and \ 32 | libpython_so.endswith(lib_ext_suffix): 33 | break 34 | else: 35 | raise FileNotFoundError(2, 'cannot find shared object file ' 36 | 'libpython3.*'+lib_ext_suffix) 37 | lib_path = os.path.abspath(os.path.dirname(__file__)) 38 | libs = \ 39 | [ 40 | libpython_so, 41 | os.path.join(lib_path, 'C10kPthread'+pyx_ext_suffix), 42 | os.path.join(lib_path, 'C10kSocket'+pyx_ext_suffix), 43 | os.path.join(lib_path, 'libc10k' +lib_ext_suffix) 44 | ] 45 | platform = sys.platform.lower() 46 | if 'linux' in platform: 47 | if 'LD_PRELOAD' in os.environ: 48 | libs = set(os.environ['LD_PRELOAD'].split() + libs) 49 | os.environ['LD_PRELOAD'] = ' '.join(libs) 50 | elif 'darwin' == platform: 51 | if 'DYLD_INSERT_LIBRARIES' in os.environ: 52 | libs = set(os.environ['DYLD_INSERT_LIBRARIES'].split() + libs) 53 | os.environ['DYLD_INSERT_LIBRARIES'] = ' '.join(libs) 54 | os.environ['DYLD_FORCE_FLAT_NAMESPACE'] = 1 55 | else: 56 | raise NotImplementedError(f'the platform "{sys.platform}" ' 57 | 'is not currently supported') 58 | if 'PATH' in os.environ: 59 | os.environ['PATH'] = bin_dir + ':' + os.environ['PATH'] 60 | else: 61 | os.environ['PATH'] = bin_dir 62 | try: 63 | p = subprocess.Popen([program] + args) 64 | except Exception as err: 65 | print (err, file=sys.stderr) 66 | return getattr(err, 'errno', 256) 67 | p.communicate() 68 | return p.returncode 69 | 70 | def parse(**kwargs): 71 | defaults = copy.copy(kwargs) 72 | arguments = defaults.pop('arguments', None) 73 | if arguments is None: 74 | arguments = sys.argv[1:] 75 | parser = ParserFactory(**defaults) 76 | args = parser.parse_args(arguments[:1]) 77 | return (args.program, arguments[1:], parser) 78 | 79 | def ParserFactory(**kwargs): 80 | parser = \ 81 | argparse.ArgumentParser( 82 | description=package__doc__, 83 | formatter_class=argparse.RawDescriptionHelpFormatter 84 | ) 85 | parser.add_argument( 86 | 'program', 87 | metavar='program', 88 | type=str, 89 | help='program to be executed.' 90 | ) 91 | parser.add_argument( 92 | 'args', 93 | metavar='arg', 94 | nargs='*', 95 | help='program arguments.' 96 | ) 97 | return parser 98 | -------------------------------------------------------------------------------- /src/c10k/_gevent_cgreenlet.h: -------------------------------------------------------------------------------- 1 | #ifndef __GEVENT_CGREENLET_H 2 | #define __GEVENT_CGREENLET_H 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | typedef struct _c10k_gevent_greenlet { 11 | PyGreenlet __pyx_base; 12 | void * __pyx_vtab; 13 | PyObject *value; 14 | PyObject *args; 15 | PyObject *kwargs; 16 | PyObject *spawning_greenlet; 17 | PyObject *spawning_stack; 18 | PyObject *spawn_tree_locals; 19 | PyObject *_links; 20 | PyObject *_exc_info; 21 | PyObject *_notifier; 22 | PyObject *_start_event; 23 | PyObject *_formatted_info; 24 | PyObject *_ident; 25 | } PyC10kGeventGreenlet; 26 | 27 | #ifdef __cplusplus 28 | } 29 | #endif 30 | #endif /* !__GEVENT_CGREENLET */ 31 | -------------------------------------------------------------------------------- /src/c10k/libc10k.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "C10kPthread.h" 4 | #include "C10kSocket.h" 5 | 6 | PyMODINIT_FUNC PyInit__greenlet (void); 7 | 8 | static int volatile libc10k_initialized = 0; 9 | static int volatile libc10k_finalized = 0; 10 | 11 | PyObject *pC10kPthreadModule = NULL; 12 | PyObject *pC10kSocketModule = NULL; 13 | 14 | void libc10k__init__() 15 | { 16 | if (libc10k_initialized) 17 | return; 18 | if (PyImport_AppendInittab( "c10k.C10kPthread", 19 | PyInit_C10kPthread) == -1) { 20 | errno = 80; 21 | perror( 22 | "c10k.C10kPthread: could not extend in-built modules table" 23 | ); 24 | exit(errno); 25 | } 26 | if (PyImport_AppendInittab( "c10k.C10kSocket", 27 | PyInit_C10kSocket) == -1) { 28 | errno = 80; 29 | perror( 30 | "c10k.C10kSocket: could not extend in-built modules table" 31 | ); 32 | exit(errno); 33 | } 34 | Py_Initialize(); 35 | pC10kPthreadModule = PyImport_ImportModule("c10k.C10kPthread"); 36 | if (NULL == pC10kPthreadModule) { 37 | errno = 80; 38 | perror("c10k.C10kPthread: ImportError"); 39 | PyErr_Print(); 40 | exit(errno); 41 | } else { 42 | C10kPthread_initialized = 1; 43 | } 44 | pC10kSocketModule = PyImport_ImportModule("c10k.C10kSocket"); 45 | if (NULL == pC10kSocketModule) { 46 | errno = 80; 47 | perror("c10k.C10kSocket: ImportError"); 48 | PyErr_Print(); 49 | exit(errno); 50 | } else { 51 | C10kSocket_initialized = 1; 52 | } 53 | libc10k_initialized = 1; 54 | } 55 | 56 | void libc10k__fini__() 57 | { 58 | if (libc10k_finalized) 59 | return; 60 | Py_XDECREF(pC10kPthreadModule); 61 | Py_XDECREF(pC10kSocketModule); 62 | if (Py_FinalizeEx() < 0) { 63 | exit(120); 64 | } 65 | libc10k_finalized = 1; 66 | } 67 | -------------------------------------------------------------------------------- /src/c10k/libc10k.setup: -------------------------------------------------------------------------------- 1 | import distutils.command.build_ext 2 | import distutils.core 3 | import distutils.extension 4 | import os.path 5 | import sys 6 | import sysconfig 7 | 8 | name = os.path.splitext(os.path.basename(__file__))[0] 9 | home = os.path.abspath(sys.path[0]) 10 | 11 | class specialized_build_ext(distutils.command.build_ext.build_ext): 12 | 13 | def get_ext_filename(self, ext_name): 14 | old_ext_suffix = sysconfig.get_config_var('EXT_SUFFIX') 15 | new_ext_suffix = os.path.splitext(old_ext_suffix)[1] 16 | return super(specialized_build_ext, self) \ 17 | .get_ext_filename(ext_name) \ 18 | .replace(old_ext_suffix, new_ext_suffix) 19 | 20 | distutils.core.setup( 21 | ext_modules=[ 22 | distutils.extension.Extension( 23 | name=name, 24 | sources=[os.path.join(home, name + '.c')], 25 | extra_link_args= 26 | [ 27 | f'-Wl,-init,{name}__init__', 28 | f'-Wl,-fini,{name}__fini__' 29 | ] 30 | ) 31 | ], 32 | cmdclass={'build_ext': specialized_build_ext} 33 | ) 34 | -------------------------------------------------------------------------------- /src/c10k/pthread.pxd: -------------------------------------------------------------------------------- 1 | cdef extern from '': 2 | 3 | ctypedef struct pthread_t: 4 | pass 5 | 6 | ctypedef struct pthread_attr_t: 7 | pass 8 | 9 | ctypedef struct pthread_once_t: 10 | pass 11 | 12 | ctypedef struct pthread_mutex_t: 13 | pass 14 | 15 | ctypedef struct pthread_mutexattr_t: 16 | pass 17 | 18 | ctypedef struct pthread_rwlock_t: 19 | pass 20 | 21 | ctypedef struct pthread_rwlockattr_t: 22 | pass 23 | 24 | ctypedef struct pthread_cond_t: 25 | pass 26 | 27 | ctypedef struct pthread_condattr_t: 28 | pass 29 | 30 | ctypedef struct pthread_spinlock_t: 31 | pass 32 | 33 | ctypedef struct pthread_barrier_t: 34 | pass 35 | 36 | ctypedef struct pthread_barrierattr_t: 37 | pass 38 | 39 | ctypedef struct pthread_key_t: 40 | pass 41 | 42 | struct sched_param: 43 | int sched_priority 44 | 45 | ctypedef struct cpu_set_t: 46 | pass 47 | 48 | ctypedef struct __clockid_t: 49 | pass 50 | 51 | enum: 52 | # Scheduling algorithms. 53 | SCHED_OTHER, # 0 54 | SCHED_FIFO, # 1 55 | SCHED_RR, # 2 56 | SCHED_BATCH, # 3 57 | SCHED_ISO, # 4 58 | SCHED_IDLE, # 5 59 | SCHED_DEADLINE, # 6 60 | SCHED_RESET_ON_FORK # 0x40000000 61 | 62 | enum: 63 | # Detach state. 64 | PTHREAD_CREATE_JOINABLE, 65 | PTHREAD_CREATE_DETACHED, 66 | # Mutex types. 67 | PTHREAD_MUTEX_TIMED_NP, 68 | PTHREAD_MUTEX_RECURSIVE_NP, 69 | PTHREAD_MUTEX_ERRORCHECK_NP, 70 | PTHREAD_MUTEX_ADAPTIVE_NP, 71 | PTHREAD_MUTEX_NORMAL, # = PTHREAD_MUTEX_TIMED_NP 72 | PTHREAD_MUTEX_RECURSIVE, # = PTHREAD_MUTEX_RECURSIVE_NP 73 | PTHREAD_MUTEX_ERRORCHECK, # = PTHREAD_MUTEX_ERRORCHECK_NP 74 | PTHREAD_MUTEX_DEFAULT, # = PTHREAD_MUTEX_NORMAL 75 | PTHREAD_MUTEX_FAST_NP, # = PTHREAD_MUTEX_TIMED_NP 76 | # Robust mutex or not flags. 77 | PTHREAD_MUTEX_STALLED, 78 | PTHREAD_MUTEX_STALLED_NP, # = PTHREAD_MUTEX_STALLED 79 | PTHREAD_MUTEX_ROBUST, 80 | PTHREAD_MUTEX_ROBUST_NP, # = PTHREAD_MUTEX_ROBUST 81 | # Mutex protocols. 82 | PTHREAD_PRIO_NONE, 83 | PTHREAD_PRIO_INHERIT, 84 | PTHREAD_PRIO_PROTECT, 85 | # Read-write lock types. 86 | PTHREAD_RWLOCK_PREFER_READER_NP, 87 | PTHREAD_RWLOCK_PREFER_WRITER_NP, 88 | PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, 89 | PTHREAD_RWLOCK_DEFAULT_NP, # = PTHREAD_RWLOCK_PREFER_READER_NP 90 | # Scheduler inheritance. 91 | PTHREAD_INHERIT_SCHED, 92 | PTHREAD_EXPLICIT_SCHED, 93 | # Scope handling. 94 | PTHREAD_SCOPE_SYSTEM, 95 | PTHREAD_SCOPE_PROCESS, 96 | # Process shared or private flag. 97 | PTHREAD_PROCESS_PRIVATE, 98 | PTHREAD_PROCESS_SHARED, 99 | # Cancellation 100 | PTHREAD_CANCEL_ENABLE, 101 | PTHREAD_CANCEL_DISABLE 102 | PTHREAD_CANCEL_DEFERRED, 103 | PTHREAD_CANCEL_ASYNCHRONOUS 104 | 105 | # Single execution handling. 106 | pthread_once_t PTHREAD_ONCE_INIT 107 | 108 | void *PTHREAD_CANCELED # ((void *) -1) 109 | 110 | ################################################################### 111 | # Thread attribute handling. # 112 | ################################################################### 113 | 114 | # Initialize thread attribute *ATTR with default attributes 115 | # (detachstate is PTHREAD_JOINABLE, scheduling policy is SCHED_OTHER, 116 | # no user-provided stack). 117 | int pthread_attr_init (pthread_attr_t *) nogil 118 | # Destroy thread attribute *ATTR. 119 | int pthread_attr_destroy (pthread_attr_t *) nogil 120 | # Get detach state attribute. 121 | int pthread_attr_getdetachstate (const pthread_attr_t *, int *) nogil 122 | # Set detach state attribute. 123 | int pthread_attr_setdetachstate (pthread_attr_t *, int) nogil 124 | # Get the size of the guard area created for stack overflow protection. 125 | int pthread_attr_getguardsize (const pthread_attr_t *, size_t *) nogil 126 | # Set the size of the guard area created for stack overflow protection. 127 | int pthread_attr_setguardsize (pthread_attr_t *, size_t) nogil 128 | # Return in *PARAM the scheduling parameters of *ATTR. 129 | int pthread_attr_getschedparam (const pthread_attr_t *, 130 | sched_param *) nogil 131 | # Set scheduling parameters (priority, etc) in *ATTR according to 132 | # PARAM. 133 | int pthread_attr_setschedparam (pthread_attr_t *, 134 | const sched_param *) nogil 135 | # Return in *POLICY the scheduling policy of *ATTR. 136 | int pthread_attr_getschedpolicy (const pthread_attr_t *, int *) nogil 137 | # Set scheduling policy in *ATTR according to POLICY. 138 | int pthread_attr_setschedpolicy (pthread_attr_t *, int) nogil 139 | # Return in *INHERIT the scheduling inheritance mode of *ATTR. 140 | int pthread_attr_getinheritsched (const pthread_attr_t *, int *) nogil 141 | # Set scheduling inheritance mode in *ATTR according to INHERIT. 142 | int pthread_attr_setinheritsched (pthread_attr_t *, int) nogil 143 | # Return in *SCOPE the scheduling contention scope of *ATTR. 144 | int pthread_attr_getscope (const pthread_attr_t *, int *) nogil 145 | # Set scheduling contention scope in *ATTR according to SCOPE. 146 | int pthread_attr_setscope (pthread_attr_t *, int) nogil 147 | # Return the previously set address for the stack. 148 | int pthread_attr_getstackaddr (const pthread_attr_t *, void **) nogil 149 | # Set the starting address of the stack of the thread to be created. 150 | # Depending on whether the stack grows up or down the value must either 151 | # be higher or lower than all the address in the memory block. The 152 | # minimal size of the block must be PTHREAD_STACK_MIN. 153 | int pthread_attr_setstackaddr (pthread_attr_t *, void *) nogil 154 | # Return the currently used minimal stack size. 155 | int pthread_attr_getstacksize (const pthread_attr_t *, size_t *) nogil 156 | # Add information about the minimum stack size needed for the thread 157 | # to be started. This size must never be less than PTHREAD_STACK_MIN 158 | # and must also not exceed the system limits. 159 | int pthread_attr_setstacksize (pthread_attr_t *, size_t) nogil 160 | # Return the previously set address for the stack. 161 | int pthread_attr_getstack (const pthread_attr_t *, void **, 162 | size_t *) nogil 163 | # The following two interfaces are intended to replace the last two. 164 | # They require setting the address as well as the size since only 165 | # setting the address will make the implementation on some 166 | # architectures impossible. 167 | int pthread_attr_setstack (pthread_attr_t *, void *, size_t) nogil 168 | # Thread created with attribute ATTR will be limited to run only on 169 | # the processors represented in CPUSET. 170 | int pthread_attr_setaffinity_np (pthread_attr_t *, size_t, 171 | const cpu_set_t *) nogil 172 | # Get bit set in CPUSET representing the processors threads created 173 | # with ATTR can run on. 174 | int pthread_attr_getaffinity_np (const pthread_attr_t *, size_t, 175 | cpu_set_t *) nogil 176 | # Get the default attributes used by pthread_create in this process. 177 | int pthread_getattr_default_np (pthread_attr_t *) nogil 178 | # Set the default attributes to be used by pthread_create in this 179 | # process. 180 | int pthread_setattr_default_np (const pthread_attr_t *) nogil 181 | 182 | ####################################################################### 183 | # Functions for handling mutex attributes. # 184 | ####################################################################### 185 | 186 | # Initialize mutex attribute object ATTR with default attributes 187 | # (kind is PTHREAD_MUTEX_TIMED_NP). 188 | int pthread_mutexattr_init (pthread_mutexattr_t *) nogil 189 | # Destroy mutex attribute object ATTR. 190 | int pthread_mutexattr_destroy (pthread_mutexattr_t *) nogil 191 | # Get the process-shared flag of the mutex attribute ATTR. 192 | int pthread_mutexattr_getpshared \ 193 | ( 194 | const pthread_mutexattr_t *, 195 | int * 196 | ) nogil 197 | # Set the process-shared flag of the mutex attribute ATTR. 198 | int pthread_mutexattr_setpshared (pthread_mutexattr_t *, int) nogil 199 | # Return in *KIND the mutex kind attribute in *ATTR. 200 | int pthread_mutexattr_gettype \ 201 | ( 202 | const pthread_mutexattr_t *, 203 | int * 204 | ) nogil 205 | # Set the mutex kind attribute in *ATTR to KIND ( 206 | # either PTHREAD_MUTEX_NORMAL, 207 | # PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_ERRORCHECK, or 208 | # PTHREAD_MUTEX_DEFAULT). 209 | int pthread_mutexattr_settype (pthread_mutexattr_t *, int) nogil 210 | # Return in *PROTOCOL the mutex protocol attribute in *ATTR. 211 | int pthread_mutexattr_getprotocol \ 212 | ( 213 | const pthread_mutexattr_t *, 214 | int * 215 | ) nogil 216 | # Set the mutex protocol attribute in *ATTR to PROTOCOL (either 217 | # PTHREAD_PRIO_NONE, PTHREAD_PRIO_INHERIT, or PTHREAD_PRIO_PROTECT). 218 | int pthread_mutexattr_setprotocol (pthread_mutexattr_t *, int) nogil 219 | # Return in *PRIOCEILING the mutex prioceiling attribute in *ATTR. 220 | int pthread_mutexattr_getprioceiling \ 221 | ( 222 | const pthread_mutexattr_t *, 223 | int * 224 | ) nogil 225 | # Set the mutex prioceiling attribute in *ATTR to PRIOCEILING. 226 | int pthread_mutexattr_setprioceiling (pthread_mutexattr_t *, int) nogil 227 | # Get the robustness flag of the mutex attribute ATTR. 228 | int pthread_mutexattr_getrobust \ 229 | ( 230 | const pthread_mutexattr_t *, 231 | int * 232 | ) nogil 233 | int pthread_mutexattr_getrobust_np \ 234 | ( 235 | const pthread_mutexattr_t *, 236 | int * 237 | ) nogil 238 | # Set the robustness flag of the mutex attribute ATTR. 239 | int pthread_mutexattr_setrobust (pthread_mutexattr_t *, int) nogil 240 | int pthread_mutexattr_setrobust_np (pthread_mutexattr_t *, int) nogil 241 | 242 | ####################################################################### 243 | # Functions for handling read-write lock attributes. # 244 | ####################################################################### 245 | 246 | # Initialize attribute object ATTR with default values. 247 | int pthread_rwlockattr_init (pthread_rwlockattr_t *) nogil 248 | # Destroy attribute object ATTR. 249 | int pthread_rwlockattr_destroy (pthread_rwlockattr_t *) nogil 250 | # Return current setting of process-shared attribute of ATTR in 251 | # PSHARED. 252 | int pthread_rwlockattr_getpshared \ 253 | ( 254 | const pthread_rwlockattr_t *, 255 | int * 256 | ) nogil 257 | # Set process-shared attribute of ATTR to PSHARED. 258 | int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *, int) nogil 259 | # Return current setting of reader/writer preference. 260 | int pthread_rwlockattr_getkind_np \ 261 | ( 262 | const pthread_rwlockattr_t *, 263 | int * 264 | ) nogil 265 | # Set reader/write preference. 266 | int pthread_rwlockattr_setkind_np (pthread_rwlockattr_t *, int) nogil 267 | 268 | ####################################################################### 269 | # Functions for handling condition variable attributes. # 270 | ####################################################################### 271 | 272 | # Initialize condition variable attribute ATTR. 273 | int pthread_condattr_init (pthread_condattr_t *) nogil 274 | # Destroy condition variable attribute ATTR. 275 | int pthread_condattr_destroy (pthread_condattr_t *) nogil 276 | # Get the process-shared flag of the condition variable attribute ATTR. 277 | int pthread_condattr_getpshared \ 278 | ( 279 | const pthread_condattr_t *, 280 | int * 281 | ) nogil 282 | 283 | # Set the process-shared flag of the condition variable attribute ATTR. 284 | int pthread_condattr_setpshared (pthread_condattr_t *, int) nogil 285 | # Get the clock selected for the condition variable attribute ATTR. 286 | int pthread_condattr_getclock \ 287 | ( 288 | const pthread_condattr_t *, 289 | __clockid_t * 290 | ) nogil 291 | # Set the clock selected for the condition variable attribute ATTR. 292 | int pthread_condattr_setclock (pthread_condattr_t *, __clockid_t) nogil 293 | 294 | # Initialize barrier attribute ATTR. 295 | int pthread_barrierattr_init (pthread_barrierattr_t *) nogil 296 | # Destroy previously dynamically initialized barrier attribute ATTR. 297 | int pthread_barrierattr_destroy (pthread_barrierattr_t *) nogil 298 | # Get the process-shared flag of the barrier attribute ATTR. 299 | int pthread_barrierattr_getpshared \ 300 | ( 301 | const pthread_barrierattr_t *, 302 | int * 303 | ) nogil 304 | # Set the process-shared flag of the barrier attribute ATTR. 305 | int pthread_barrierattr_setpshared (pthread_barrierattr_t *, int) nogil 306 | --------------------------------------------------------------------------------