Monday, 28 October 2013

Few Clarifications

Following in from the design issue discussed earlier, as we realized we could not completely replace select with epoll, there had to be macros involved.
Fallback options : select - to make sure in the absence of epoll, boa could work with the original configuration.
And hence we considered the option of checking the type of the system, which was just a check on the predefined macros __linux and __APPLE__.

But was this check enough?
Linux has inbuilt epoll support from kernel version 2.5.44.
Is it enough to check the kind of system that is and assume that the feature is supported?
I was not sure. Hence, the double check. Found a piece of code which claimed to check for epoll support across systems [1]. Considered to use it in the epoll implementation to make a choice.


Another realization that came our way was that we needn't change the request structure itself, instead build the code around it. The request structure could remain the same way and function as it always did.

Also, as mentioned in the comment and the previous blog post [2] we do not have to consider altering the setting of the max connections as it is set to RLIMIT_NOFILE. Even though epoll may not have a limit on the maximum number of clients connected, but system limits have to be always accounted for. Also, setting the value to RLIMIT_INFINITY could cause some system dependent issues.


[1] http://www.gnu.org/software/autoconf-archive/ax_have_epoll.html
[2] http://a-voyage-into-the-land-of-boa.blogspot.in/2013/10/first-glance-at-code.html

Monday, 21 October 2013

Choosing a Mode of Execution: A Design Issue

An important aspect to examine prior to diving into the actual implementation is the design issue regarding choice of modes among select, epoll and kqueue.

Several possible solutions exist. We shall consider ones that appear most relevant.

Case 1: 
Replacing select in its entirety with either epoll or kqueue
As a convenience to the user, it makes sense to take the responsibility of choosing the path away from the user; make it in-built. 
Since the choice is only among 2 options, usage of macros would be a convenient solution.[1]
That's pretty nifty.

As our primary aim is to provide an enhancement to the web server, augmenting extensibility features will be an added advantage. The code can be made generic, adapting a common structure to handle requests through either approach. The function activated can depend on the macro chosen in as per the approach declared previously.

struct kevent {
             uintptr_t       ident;          /* identifier for this event */
             int16_t         filter;         /* filter for event */
             uint16_t        flags;          /* general flags */
             uint32_t        fflags;         /* filter-specific flags */
             intptr_t        data;           /* filter-specific data */
             void            *udata;         /* opaque user data identifier */
     };

typedef union epoll_data {
               void    *ptr;
               int      fd;
               uint32_t u32;
               uint64_t u64;
} epoll_data_t;

struct epoll_event {
               uint32_t     events;    /* Epoll events */
               epoll_data_t data;      /* User data variable */
};

We have provided the corresponding kqueue and epoll structures for reference.

            
Case 2: 
Keeping select implementation, and having a choice between select and epoll/kqueue

This approach is an extension of the above. The user has a choice to either use select or an event mechanism (ie epoll/kqeueue. This choice will be made inherently depending on the type of the system)

Code modules have a design potential.[2] But they might be an overkill with respect to BOA. 

            
Case 3: 
The choice among select, epoll and kqueue is left to the user.

You might wonder whether this is really advisable. After all, the user must not be bothered with implementation technicality. But, in the future, there may arise an operating system that provides libraries containing both epoll and kqueue.[3] Perhaps a user extremely particular about performance with the knowledge of the type of traffic expected will also find this useful.

In the actual code, a three-way switch will comfortably handle this circumstance.

Note regarding kFreeBSD: (see link [3])
Apparently you can run both Linux and FreeBSD binaries on it. It supports calls up to Linux version 2.6.18. But, using macros here will result in only epoll being used. (we check for __APPLE__ and not FreeBSD. This operating system will fall under __UNIX__ flag.)


The situation appears thus, having articulated possible solutions. We do hope for your valuable suggestions or additions. They would be most helpful in making an appropriate choice.



Monday, 14 October 2013

Determining what to Change


God grant me the serenity to accept the things I cannot change, the courage to change the things I can, and the wisdom to know the difference.

This wisdom is generally what we may lack at the crucial time when the code is handled for changing. We change things that might have had other impacts, dependencies and as a result of which our entire effort might just have to be redone.

Following in from the previous brief discussion of the various function calls made, we can clearly distinguish between the two groups.

The major goal of the entire project being the transition from the use of select to efficiently make use of the epoll mechanism, the majority of the work involved in playing with socket based calls. It is clear that no initialization functions need any sort of tweaks.

The file or the function that has to be majorly changed is of course select_loop( ) itself!
The file select.c contains the major logic of the select statement which needs to be adapted for epoll.
Also, the processing is done in the form of queues. Three different types of queues are used for processing the requests. These do not require any major changes but for the dependence on their use of the structure request.

Examining dependencies further, we come across a structure - struct request which stores the incoming request details and is further used for processing the actual request. Defined in the globals.h file, it is now marked for change to incorporate the epoll based event structure.

A deluge of pointers awaits as we explore the files request.c and response.c. Mainly used for processing the request structure, they become potential candidates and so does buffer.c which contains functions which help in buffering the data before sending it to the client. To he file, get.c performs a part to get the headers of the incoming request. Reading and writing involves the use of pipes and hence the file, pipe.c is another contender. Inspecting further, it is found that the file cgi.c may need minor tweaks for it uses the file descriptor from the request structure.

Here, we have now enumerated the ones that possibly need to be changed. Now let us look at them in detail so as to understand them better.