| <html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Rivet Internals</title><link rel="stylesheet" type="text/css" href="rivet.css"><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"><link rel="home" href="index.html" title="Apache Rivet"><link rel="up" href="index.html" title="Apache Rivet"><link rel="prev" href="help.html" title="Resources - How to Get Help"><link rel="next" href="upgrading.html" title="Upgrading from mod_dtcl or NeoWebScript"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Rivet Internals</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="help.html"><img src="images/prev.png" alt="Prev"></a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="upgrading.html"><img src="images/next.png" alt="Next"></a></td></tr></table></div><div class="section"><div class="titlepage"><div><div><hr><h2 class="title" style="clear: both"><a name="internals"></a>Rivet Internals</h2></div></div></div><p style="width:90%"> |
| This section easily falls out of date, as new code is added, old |
| code is removed, and changes are made. The best place to look |
| is the source code itself. If you are interested in the changes |
| themselves, the Subversion revision control system |
| (<span style="font-family:monospace"><span class="command"><strong>svn</strong></span></span>) can provide you with information about |
| what has been happening with the code. |
| </p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idm4154"></a>Initialization</h3></div></div></div><p style="width:90%"> |
| When Apache is started, (or when child Apache processes are |
| started if a threaded Tcl is used), |
| <code class="function">Rivet_InitTclStuff</code> is called, which |
| creates a new interpreter, or one interpreter per virtual |
| host, depending on the configuration. It also initializes |
| various things, like the <span class="structname">RivetChan</span> |
| channel system, creates the Rivet-specific Tcl commands, and |
| executes Rivet's <code class="filename">init.tcl</code>. The caching |
| system is also set up, and if there is a |
| <span style="font-family:monospace"><span class="command"><strong>GlobalInitScript</strong></span></span>, it is run. |
| </p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idm4161"></a>RivetChan</h3></div></div></div><p style="width:90%"> |
| The <span class="structname">RivetChan</span> system was created in |
| order to have an actual Tcl channel that we could redirect |
| standard output to. This lets us use, for instance, the |
| regular <span style="font-family:monospace"><span class="command"><strong>puts</strong></span></span> command in .rvt pages. It |
| works by creating a channel that buffers output, and, at |
| predetermined times, passes it on to Apache's IO system. |
| Tcl's regular standard output is replaced with an instance of |
| this channel type, so that, by default, output will go to the |
| web page. |
| </p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idm4166"></a>The <span style="font-family:monospace"><span class="command"><strong>global</strong></span></span> Command</h3></div></div></div><p style="width:90%"> |
| Rivet aims to run standard Tcl code with as few surprises as |
| possible. At times this involves some compromises - in this |
| case regarding the <span style="font-family:monospace"><span class="command"><strong>global</strong></span></span> command. The |
| problem is that the command will create truly global |
| variables. If the user is just cut'n'pasting some Tcl code |
| into Rivet, they most likely just want to be able to share the |
| variable in question with other procs, and don't really care |
| if the variable is actually persistant between pages. The |
| solution we have created is to create a proc |
| <span style="font-family:monospace"><span class="command"><strong>::request::global</strong></span></span> that takes the place of |
| the <span style="font-family:monospace"><span class="command"><strong>global</strong></span></span> command in Rivet templates. If |
| you really need a true global variable, use either |
| <span style="font-family:monospace"><span class="command"><strong>::global</strong></span></span> or add the :: namespace qualifier |
| to variables you wish to make global. |
| </p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idm4174"></a>Page Parsing, Execution and Caching</h3></div></div></div><p style="width:90%"> |
| When a Rivet page is requested, it is transformed into an |
| ordinary Tcl script by parsing the file for the <? ?> |
| processing instruction tags. Everything outside these tags |
| becomes a large <span style="font-family:monospace"><span class="command"><strong>puts</strong></span></span> statement, and |
| everything inside them remains Tcl code. |
| </p><p style="width:90%"> |
| Each .rvt file is evaluated in its own |
| <code class="constant">::request</code> namespace, so that it is not |
| necessary to create and tear down interpreters after each |
| page. By running in its own namespace, though, each page will |
| not run afoul of local variables created by other scripts, |
| because they will be deleted automatically when the namespace |
| goes away after Apache finishes handling the request. |
| </p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"> |
| One current problem with this system is that while |
| variables are garbage collected, file handles are not, so |
| that it is very important that Rivet script authors make |
| sure to close all the files they open. |
| </td></tr></table></div><p style="width:90%"> |
| </p><p style="width:90%"> |
| After a script has been loaded and parsed into it's "pure Tcl" |
| form, it is also cached, so that it may be used in the future |
| without having to reload it (and re-parse it) from the disk. |
| The number of scripts stored in memory is configurable. This |
| feature can significantly improve performance. |
| </p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idm4182"></a>Extending Rivet by developing C procedures implementing new commands</h3></div></div></div><p style="width:90%"> |
| Rivet endows the Tcl interpreter with new commands |
| serving as interface between the application layer and the |
| Apache web server. Many of these commands |
| are meaningful only when a HTTP request is under way and |
| therefore a request_rec object allocated by the framework |
| is existing and was passed to mod_rivet as argument of a callback. |
| In case commands have to gain access to a valid request_rec |
| object the C procedure must check if such |
| a pointer exists and it's initialized |
| with valid data. For this purpose the procedure handling requests |
| (Rivet_SendContent) makes a copy of such pointer and keeps it |
| in an internal structure. The copy is set to NULL just before |
| returning to the framework, right after mod_rivet's has |
| carried out its request processing. When the pointer copy is NULL |
| the module is outside any request processing and this |
| condition invalidates the execution of |
| many of the Rivet commands. In case they are called |
| (for example in a ChildInitScript, GlobalInitScript, |
| ServerInitScript or ChildExitScript) they fail with a Tcl error |
| you can handle with a <span style="font-family:monospace"><span class="command"><strong>catch</strong></span></span> command. |
| </p><p style="width:90%"> |
| For this purpose in src/rivet.h the macro |
| CHECK_REQUEST_REC was defined accepting two arguments: the copy |
| to the request_rec pointer (stored in the |
| <span class="structname">rivet_interp_globals</span> |
| structure) and the command name. If the pointer is NULL |
| the macro calls Tcl_NoRequestRec and returns TCL_ERROR |
| causing the command to fail. These are the step to follow |
| to implement a new C language command for mod_rivet |
| </p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"> |
| Define the command and associated C language procedure |
| in src/rivetcmds/rivetCore.c using the macro |
| RIVET_OBJ_CMD<pre class="programlisting">RIVET_OBJ_CMD("mycmd",Rivet_MyCmd)</pre> |
| This macro ensures the command is defined as <span style="font-family:monospace"><span class="command"><strong>::rivet::mycmd</strong></span></span></li><li class="listitem"> |
| Add the code of Rivet_MyCmd to src/rivetcmd/rivetCore.c (in case |
| the code resides in a different file also src/Makefile.am should be |
| changed to tell the build system how to compile the code and |
| link it into mod_rivet.so) |
| </li><li class="listitem"> |
| If the code must gain access to <span style="font-family:monospace"><span class="command"><strong>globals->r</strong></span></span> |
| put add the macro testing for the pointer |
| <pre class="programlisting">TCL_CMD_HEADER( Rivet_MyCmd ) |
| { |
| rivet_interp_globals *globals = Tcl_GetAssocData( interp, "rivet", NULL ); |
| .... |
| CHECK_REQUEST_REC(globals->r,"::rivet::mycmd"); |
| ... |
| }</pre></li><li class="listitem"> |
| Add a test for this command in tests/checkfails.tcl. For |
| instance |
| <pre class="programlisting">... |
| check_fail no_body |
| check_fail virtual_filename unkn |
| check_fail my_cmd <arg1> <arg2> |
| ....</pre> |
| Where <arg1> <arg2> are optional |
| arguments in case the command needs to check for <span style="font-family:monospace"><span class="command"><strong>globals->r</strong></span></span> |
| in special cases. Then, if <span style="font-family:monospace"><span class="command"><strong>::rivet::mycmd</strong></span></span> must fail also |
| tests/failtest.tcl should modified as |
| <pre class="programlisting">virtual_filename->1 |
| mycmd->1</pre> |
| The value associated to the test must be 0 in case the |
| command doesn't need to test the <span style="font-family:monospace"><span class="command"><strong>globals->r</strong></span></span> pointer. |
| </li></ul></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idm4208"></a>Debugging Rivet and Apache</h3></div></div></div><p style="width:90%"> |
| If you are interested in hacking on Rivet, you're welcome to |
| contribute! Invariably, when working with code, things go |
| wrong, and it's necessary to do some debugging. In a server |
| environment like Apache, it can be a bit more difficult to |
| find the right way to do this. Here are some techniques to |
| try. |
| </p><p style="width:90%"> |
| The first thing you should know is that Apache can be launched |
| as a <span class="emphasis"><em>single process</em></span> with the |
| -X argument:</p><pre class="programlisting">httpd -X</pre>. |
| <p style="width:90%"> |
| On Linux, one of the first things to try is the system call |
| tracer, <span style="font-family:monospace"><span class="command"><strong>strace</strong></span></span>. You don't even have to |
| recompile Rivet or Apache for this to work. |
| </p><pre class="programlisting">strace -o /tmp/outputfile -S 1000 httpd -X</pre><p style="width:90%"> |
| This command will run httpd in the system call tracer, |
| which leaves its output (there is potentially a lot of it) in |
| <code class="filename">/tmp/outputfile</code>. The -S |
| option tells <span style="font-family:monospace"><span class="command"><strong></strong></span></span>strace to only record the |
| first 1000 bytes of a syscall. Some calls such as |
| <code class="function">write</code> can potentially be much longer than |
| this, so you may want to increase this number. The results |
| are a list of all the system calls made by the program. You |
| want to look at the end, where the failure presumably occured, |
| to see if you can find anything that looks like an error. If |
| you're not sure what to make of the results, you can always |
| ask on the Rivet development mailing list. |
| </p><p style="width:90%"> |
| If <span style="font-family:monospace"><span class="command"><strong>strace</strong></span></span> (or its equivalent on your |
| operating system) doesn't answer your question, it may be time |
| to debug Apache and Rivet. To do this, you will need to rebuild mod_rivet. |
| First of all you have to configure the build by running the |
| <span style="font-family:monospace"><span class="command"><strong>./configure</strong></span></span> script with the |
| -enable-symbols option and after you have |
| set the CFLAGS and LDFLAGS environment variables |
| </p><pre class="programlisting">export CFLAGS="-g -O0" |
| export LDFLAGS="-g" |
| ./configure --enable-symbols ...... |
| make |
| make install</pre><p style="width:90%"> |
| Arguments to <span style="font-family:monospace"><span class="command"><strong>./configure</strong></span></span> must fit your Apache HTTP |
| web server installation. See the output produced by |
| </p><pre class="programlisting">./configure --help</pre><p style="width:90%"> |
| And check the <a class="xref" href="installation.html" title="Apache Rivet Installation">the section called “Apache Rivet Installation”</a> page to |
| have further information. |
| Since it's easier to debug a single process, we'll still run |
| Apache in single process mode with -X: |
| </p><pre class="programlisting"> |
| @ashland [~] $ gdb /usr/sbin/apache.dbg |
| GNU gdb 5.3-debian |
| Copyright 2002 Free Software Foundation, Inc. |
| GDB is free software, covered by the GNU General Public License, and you are |
| welcome to change it and/or distribute copies of it under certain conditions. |
| Type "show copying" to see the conditions. |
| There is absolutely no warranty for GDB. Type "show warranty" for details. |
| This GDB was configured as "powerpc-linux"... |
| (gdb) run -X |
| Starting program: /usr/sbin/apache.dbg -X |
| [New Thread 16384 (LWP 13598)] |
| . |
| . |
| . |
| </pre><p style="width:90%"> |
| When your apache session is up and running, you can request a |
| web page with the browser, and see where things go wrong (if |
| you are dealing with a crash, for instance). |
| </p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="help.html"><img src="images/prev.png" alt="Prev"></a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="upgrading.html"><img src="images/next.png" alt="Next"></a></td></tr><tr><td width="40%" align="left" valign="top">Resources - How to Get Help </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.png" alt="Home"></a></td><td width="40%" align="right" valign="top"> Upgrading from mod_dtcl or NeoWebScript</td></tr></table></div></body></html> |