Select Event Loop Sample in C++

The Select Event Loop sample demonstrates how to add HTTP server functionality to your C application and use a POSIX select event loop to wait for I/O events. AppWeb offers several methods to wait for events. See the Programming Paradigms document for further information.

The sample is a single-threaded main program that listens on port 8888 for HTTP requests.

See also the equivalent C selectEventLoop sample.

Files

selectEventLoop.conf
selectEventLoop.cpp

Configuration File

selectEventLoop.conf

DocumentRoot "."
Listen 8888
ThreadLimit 0

LoadModule ejs ../../../lib/libejsModule
LoadModule egi ../../../lib/libegiHandler
LoadModule esp ../../../lib/libespHandler
LoadModule static ../../../lib/libcopyHandler

AddHandler egiHandler .egi
AddHandler espHandler .esp
AddHandler copyHandler

This configuration file loads the embedded javascript module and the embedded server pages and embedded gateway interface, and static content handlers. It is configured to run single-threaded. It assumes that the sample is being run from the C/selectEventLoop directory. Modify these module paths to suit your installation.

You should modify the DocumentRoot and Listen directives to suit your application's needs.

Source Code

selectEventLoop.cpp

//
// Copyright (c) Mbedthis Software LLC, 2003-2004. All Rights Reserved.
//
/// @file selectEventLoop.cpp
/// @brief Embed the AppWeb server in a single-threaded program using
/// a select event loop.
///

/////////////////////////////// Includes ///////////////////////////////

#include "appWeb/appWeb.h"

//////////////////////////// Forward Declarations //////////////////////

static void eventLoop();

/////////////////////////////////// Code ///////////////////////////////

int main(int argc, char** argv)
{
MaHttp *http; // Http service inside our app
MaServer *server; // For the HTTP server
Mpr mpr("selectEventLoop"); // Initialize the run time

#if MPR_FEATURE_LOG
//
// Do the following two statements only if you want debug trace
//
mpr.addListener(new MprLogToFile());
mpr.setLogSpec("stdout:4");
#endif

//
// Start the Mbedthis Portable Runtime and request single threading
//
mpr.start(0);

//
// Create Http and Server objects for this application. We set the
// ServerName to be "default" and the initial serverRoot to be ".".
// This will be overridden in selectEventLoop.conf.
//
http = new MaHttp();
server = new MaServer(http, "default", ".");

//
// Configure the server with the configuration directive file
//
if (server->configure("selectEventLoop.conf", 0) < 0) {
mprFprintf(MPR_STDERR,
"Can't configure the server. Error on line %d\n",
server->getLine());
exit(2);
}

//
// Start the server
//
if (http->start() < 0) {
mprFprintf(MPR_STDERR, "Can't start the server\n");
exit(2);
}

//
// Service incoming requests until time to exit.
//
eventLoop();

//
// Orderly shutdown
//
http->stop();
delete server;
delete http;

//
// MPR run-time will automatically stop and be cleaned up
//
return 0;
}

////////////////////////////////////////////////////////////////////////
//
// Sample main event loop using select. This demonstrates how to
// integrate AppWeb with your applications event loop using select()
//

static void eventLoop()
{
struct timeval timeout;
fd_set readFds, writeFds, exceptFds;
fd_set readInterest, writeInterest, exceptInterest;
#if WIN
fd_set *readp, *writep, *exceptp;
#endif
Mpr *mpr;
int maxFd, till, lastGet, readyFds;

mpr = mprGetMpr();
lastGet = -1;
maxFd = 0;
FD_ZERO(&readInterest);
FD_ZERO(&writeInterest);
FD_ZERO(&exceptInterest);

while (!mpr->isExiting()) {

if (mpr->runTimers() > 0) {
till = 0;
} else {
till = mpr->getIdleTime();
}

//
// This will run tasks if maxThreads == 0 (single threaded). If
// multithreaded, the thread pool will run tasks
//
if (mpr->runTasks() > 0) { // Returns > 0 if more work to do
till = 0; // So don't block in select
}

//
// Mpr will populate with the FDs in use by MR on if necessary
//
if (mpr->getFds(&readInterest, &writeInterest, &exceptInterest,
&maxFd, &lastGet)) {
//
// Masks have been rebuilt, so add user fds here ....
//
}

//
// Copy as select will modify readFds etc.
//
memcpy((void*) &readFds, (void*) &readInterest, sizeof(readFds));
memcpy((void*) &writeFds, (void*) &writeInterest, sizeof(readFds));
memcpy((void*) &exceptFds, (void*) &exceptInterest, sizeof(exceptFds));

timeout.tv_sec = till / 1000;
timeout.tv_usec = (till % 1000) * 1000;

#if WIN
//
// Windows does not accept empty descriptor arrays
//
readp = (readFds.fd_count == 0) ? 0 : &readFds;
writep = (writeFds.fd_count == 0) ? 0 : &writeFds;
exceptp = (exceptFds.fd_count == 0) ? 0 : &exceptFds;
readyFds = select(maxFd, readp, writep, exceptp, &timeout);
#else
readyFds = select(maxFd, &readFds, &writeFds, &exceptFds, &timeout);
#endif

if (readyFds > 0) {
mpr->serviceIO(readyFds, &readFds, &writeFds, &exceptFds);
}
}
}





© Mbedthis Software LLC, 2003-2204. All rights reserved. Mbedthis is a trademark of Mbedthis Software LLC.