| <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> |
| <html> |
| <head> |
| <title>4.2 Callbacks </title> |
| <META NAME="description" CONTENT="4.2 Callbacks "> |
| <META NAME="keywords" CONTENT="pyOpenSSL"> |
| <META NAME="resource-type" CONTENT="document"> |
| <META NAME="distribution" CONTENT="global"> |
| <link rel="STYLESHEET" href="pyOpenSSL.css"> |
| <LINK REL="next" href="socket-methods.html"> |
| <LINK REL="previous" href="exceptions.html"> |
| <LINK REL="up" href="internals.html"> |
| <LINK REL="next" href="socket-methods.html"> |
| </head> |
| <body> |
| <DIV CLASS="navigation"> |
| <table align="center" width="100%" cellpadding="0" cellspacing="2"> |
| <tr> |
| <td><A href="exceptions.html"><img src="previous.gif" |
| border="0" height="32" |
| alt="Previous Page" width="32"></A></td> |
| <td><A href="internals.html"><img src="up.gif" |
| border="0" height="32" |
| alt="Up One Level" width="32"></A></td> |
| <td><A href="socket-methods.html"><img src="next.gif" |
| border="0" height="32" |
| alt="Next Page" width="32"></A></td> |
| <td align="center" width="100%">Python OpenSSL Manual</td> |
| <td><A href="contents.html"><img src="contents.gif" |
| border="0" height="32" |
| alt="Contents" width="32"></A></td> |
| <td><img src="blank.gif" |
| border="0" height="32" |
| alt="" width="32"></td> |
| <td><img src="blank.gif" |
| border="0" height="32" |
| alt="" width="32"></td> |
| </tr></table> |
| <b class="navlabel">Previous:</b> <a class="sectref" href="exceptions.html">4.1 Exceptions</A> |
| <b class="navlabel">Up:</b> <a class="sectref" href="internals.html">4 Internals</A> |
| <b class="navlabel">Next:</b> <a class="sectref" href="socket-methods.html">4.3 Acessing Socket Methods</A> |
| <br><hr> |
| </DIV> |
| <!--End of Navigation Panel--> |
| |
| <H2><A NAME="SECTION000520000000000000000"> </A> |
| <BR> |
| 4.2 Callbacks |
| </H2> |
| |
| <P> |
| There are a number of problems with callbacks. First of all, OpenSSL is written |
| as a C library, it's not meant to have Python callbacks, so a way around that |
| is needed. Another problem is thread support. A lot of the OpenSSL I/O |
| functions can block if the socket is in blocking mode, and then you want other |
| Python threads to be able to do other things. The real trouble is if you've |
| released the global CPython interpreter lock to do a potentially blocking |
| operation, and the operation calls a callback. Then we must take the GIL back, |
| since calling Python APIs without holding it is not allowed. |
| |
| <P> |
| There are two solutions to the first problem, both of which are necessary. The |
| first solution to use is if the C callback allows ''userdata'' to be passed to |
| it (an arbitrary pointer normally). This is great! We can set our Python |
| function object as the real userdata and emulate userdata for the Python |
| function in another way. The other solution can be used if an object with an |
| ''app_data'' system always is passed to the callback. For example, the SSL |
| object in OpenSSL has app_data functions and in e.g. the verification |
| callbacks, you can retrieve the related SSL object. What we do is to set our |
| wrapper <tt class="class">Connection</tt> object as app_data for the SSL object, and we can |
| easily find the Python callback. |
| |
| <P> |
| The other problem is solved using thread local variables. Whenever the GIL is |
| released before calling into an OpenSSL API, the PyThreadState pointer returned |
| by <tt class="cfunction">PyEval_SaveState</tt> is stored in a global thread local variable |
| (using Python's own TLS API, <tt class="cfunction">PyThread_set_key_value</tt>). When it is |
| necessary to re-acquire the GIL, either after the OpenSSL API returns or in a C |
| callback invoked by that OpenSSL API, the value of the thread local variable is |
| retrieved (<tt class="cfunction">PyThread_get_key_value</tt>) and used to re-acquire the GIL. |
| This allows Python threads to execute while OpenSSL APIs are running and allows |
| use of any particular pyOpenSSL object from any Python thread, since there is |
| no per-thread state associated with any of these objects and since OpenSSL is |
| threadsafe (as long as properly initialized, as pyOpenSSL initializes it). |
| |
| <P> |
| |
| <DIV CLASS="navigation"> |
| <p><hr> |
| <table align="center" width="100%" cellpadding="0" cellspacing="2"> |
| <tr> |
| <td><A href="exceptions.html"><img src="previous.gif" |
| border="0" height="32" |
| alt="Previous Page" width="32"></A></td> |
| <td><A href="internals.html"><img src="up.gif" |
| border="0" height="32" |
| alt="Up One Level" width="32"></A></td> |
| <td><A href="socket-methods.html"><img src="next.gif" |
| border="0" height="32" |
| alt="Next Page" width="32"></A></td> |
| <td align="center" width="100%">Python OpenSSL Manual</td> |
| <td><A href="contents.html"><img src="contents.gif" |
| border="0" height="32" |
| alt="Contents" width="32"></A></td> |
| <td><img src="blank.gif" |
| border="0" height="32" |
| alt="" width="32"></td> |
| <td><img src="blank.gif" |
| border="0" height="32" |
| alt="" width="32"></td> |
| </tr></table> |
| <b class="navlabel">Previous:</b> <a class="sectref" href="exceptions.html">4.1 Exceptions</A> |
| <b class="navlabel">Up:</b> <a class="sectref" href="internals.html">4 Internals</A> |
| <b class="navlabel">Next:</b> <a class="sectref" href="socket-methods.html">4.3 Acessing Socket Methods</A> |
| <hr> |
| <span class="release-info">Release 0.12.</span> |
| </DIV> |
| <!--End of Navigation Panel--> |
| |
| </BODY> |
| </HTML> |