#ifndef __CurrentRequest_h_ #define __CurrentRequest_h_ #include "Messages.h" /* What request are we currently servicing? * * Note that this is not filled in automatically. There are several different * libraries that help you manage an event loop. Some threads create their * own event loops. If you want to read a value from here, generally speaking * it's your responsiblity to make sure it's in here to begin with. * * Typically a thread will grab a request from a queue, store it in a local * variable, then other code can read that variable. Sometimes the request * object will be passed to a procedure, which might pass it to another, * procedure, and another.... * * We often try to organize the code so there's less sharing. The switch * statement in a thread's event loop will extract information from a request * and pass only the minimum amount of information to various procedures. * The other procedures know as little as possible. Sometimes we pass the * entire request because we still need a request, e.g. we're going to put it * into another queue. Sometimes we pass the entire request because there is a * lot of interesting data all grouped together, and we don't want to have a * series of procedures all with a long list of individual inputs. * * CurrentRequest becomes espeically intersting in ../tikiller/. That project * has an unusual number of layers. It's often hard to pass relevant * information through all of the layers. We've been moving toward more * thread variables, like we are using here, to make information available. * * Although tikiller is the first program to use CurrentRequest, CurrentRequest * is very generic and could be used by other programs. That's part of the * reason this file is in the shared/ directory. Another reason is that we * might want other library files, like ContainerThread.[Ch] to access this * file. ContainerThread provides a reusable event loop, and it might make * sense for that file to automatically provide the current request to this * file. */ class CurrentRequest { private: static __thread Request *_current; public: // What is the currently active request? Returns NULL if there isn't one // and/or we don't know. static Request *get() { return _current; } // What socket is associated with the currently active request. Returns // null if // o we don't know the currently active request, // o there is no currently active request, or // o the currently active request has no socket associated with it. static SocketInfo *getSocketInfo() { return _current?_current->getSocketInfo():NULL; } // Create one of these objects to set the current request. The current // request will automatically return to NULL when this goes out of scope. // // This works on the "simple" assumption that only one of these objects // will be active at a time. It's certainly possible that while processing // one request you start processing other requests. ContainerThread, for // example, will often use one request as a wrapper around another request. // If and when we deal with that, we'll need another class, rather than // Simple. For now if someone sets the active request while a request // is already active, I'll assume that was a mistake. class Simple { public: Simple(Request *current) { assert(!_current) ; _current = current; } ~Simple() { _current = NULL; } }; // Create one of these objects to set the current request. The current // request will automatically return to its previous value when this goes out // of scope. // // This uses a little more memory and CPU than Simple. class Recursive { private: Request *const _previous; public: Recursive(Request *current) : _previous(_current) { _current = current; } ~Recursive() { _current = _previous; } }; }; #endif