📄 sequencer.cc
字号:
// $Header: /cvsroot/sourcenav/src/snavigator/demo/c++_demo/glish/Sequencer.cc,v 1.1.1.1 2002/04/18 23:35:25 mdejong Exp $#include "system.h"#include <stdlib.h>#include <string.h>#include <stream.h>#include <osfcn.h>#include <sys/param.h>#include <sys/types.h>#ifdef HAVE_SIGPROCMASK#include <signal.h>#endif#ifdef HAVE_SYS_SELECT_H#include <sys/select.h>#endif#ifndef MAXHOSTNAMELEN#define MAXHOSTNAMELEN 64#endifextern "C" {char* getenv( const char* );int isatty( int fd );int system( const char* string );}#include "Reporter.h"#include "Sequencer.h"#include "Frame.h"#include "BuiltIn.h"#include "Task.h"#include "input.h"#include "Channel.h"#include "Select.h"#include "Socket.h"#include "ports.h"#include "version.h"#define GLISH_RC_FILE ".glishrc"// Time to wait until probing a remote daemon, in seconds.#define PROBE_DELAY 5// Interval between subsequent probes, in seconds.#define PROBE_INTERVAL 5// A Selectee corresponding to input for a Glish client.class ClientSelectee : public Selectee { public: ClientSelectee( Sequencer* s, Task* t ); int NotifyOfSelection(); protected: Sequencer* sequencer; Task* task; };// A Selectee used only to intercept the initial "established" event// generated by a local Glish client. Because we communicate with these// clients using pipes instead of sockets, we can't use the AcceptSelectee// (see below) to recognize when they're connecting.class LocalClientSelectee : public Selectee { public: LocalClientSelectee( Sequencer* s, Channel* c ); int NotifyOfSelection(); protected: Sequencer* sequencer; Channel* chan; };// A Selectee corresponding to a new request of a client to connect// to the sequencer.class AcceptSelectee : public Selectee { public: AcceptSelectee( Sequencer* s, Socket* conn_socket ); int NotifyOfSelection(); protected: Sequencer* sequencer; Socket* connection_socket; };// A Selectee corresponding to a Glish script's own client.class ScriptSelectee : public Selectee {public: ScriptSelectee( Client* client, Agent* agent, int conn_socket ); int NotifyOfSelection();protected: Client* script_client; Agent* script_agent; int connection_socket; };// A Selectee for detecting user input.class UserInputSelectee : public Selectee {public: UserInputSelectee( int user_fd ) : Selectee( user_fd ) { } // Indicate user input available by signalling to end the // select. int NotifyOfSelection() { return 1; } };// A Selectee for detecting Glish daemon activity.class DaemonSelectee : public Selectee {public: DaemonSelectee( RemoteDaemon* daemon, Selector* sel, Sequencer* s ); int NotifyOfSelection();protected: RemoteDaemon* daemon; Selector* selector; Sequencer* sequencer; };// A SelectTimer for handling glishd probes.class ProbeTimer : public SelectTimer {public: ProbeTimer( PDict(RemoteDaemon)* daemons, Sequencer* s );protected: int DoExpiration(); PDict(RemoteDaemon)* daemons; Sequencer* sequencer; };// A special type of Client used for script clients. It overrides// FD_Change() to create or delete ScriptSelectee's as needed.class ScriptClient : public Client {public: ScriptClient( int& argc, char** argv ); // Inform the ScriptClient as to which selector and agent // it should use for getting and propagating events. void SetInterface( Selector* selector, Agent* agent );protected: void FD_Change( int fd, int add_flag ); Selector* selector; Agent* agent; };// A special type of Agent used for script clients; when it receives// an event, it propagates it via the ScriptClient object.class ScriptAgent : public Agent {public: ScriptAgent( Sequencer* s, Client* c ) : Agent(s) { client = c; } Value* SendEvent( const char* event_name, parameter_list* args, int /* is_request */, int /* log */ ) { Value* event_val = BuildEventValue( args, 1 ); client->PostEvent( event_name, event_val ); Unref( event_val ); return 0; }protected: Client* client; };// A RemoteDaemon keeps track of a glishd running on a remote host.// This includes the Channel used to communicate with the daemon and// modifiable state indicating whether we're currently waiting for// a probe response from the daemon.// Possible states a daemon can be in.typedef enum { DAEMON_OK, // all is okay DAEMON_REPLY_PENDING, // we're waiting for reply to last probe DAEMON_LOST // we've lost connectivity } daemon_states;class RemoteDaemon {public: RemoteDaemon( const char* daemon_host, Channel* channel ) { host = daemon_host; chan = channel; SetState( DAEMON_OK ); } const char* Host() { return host; } Channel* DaemonChannel() { return chan; } daemon_states State() { return state; } void SetState( daemon_states s ) { state = s; }protected: const char* host; Channel* chan; daemon_states state; };Notification::Notification( Agent* arg_notifier, const char* arg_field, Value* arg_value, Notifiee* arg_notifiee ) { notifier = arg_notifier; field = strdup( arg_field ); value = arg_value; notifiee = arg_notifiee; Ref( value ); }Notification::~Notification() { delete field; Unref( value ); }void Notification::Describe( ostream& s ) const { s << "notification of "; notifier->DescribeSelf( s ); s << "." << field << " ("; value->DescribeSelf( s ); s << ") for "; notifiee->stmt->DescribeSelf( s ); }Sequencer::Sequencer( int& argc, char**& argv ) { init_reporters(); init_values(); // Create the global scope. scopes.append( new expr_dict ); create_built_ins( this ); null_stmt = new NullStmt; stmts = null_stmt; last_task_id = my_id = 1; await_stmt = except_stmt = 0; await_only_flag = 0; pending_task = 0; maximize_num_fds(); // avoid SIGPIPE's - they can occur if a client's termination // is not detected prior to sending an event to the client#ifdef HAVE_SIGPROCMASK sigset_t sig_mask; sigemptyset( &sig_mask ); sigaddset( &sig_mask, SIGPIPE ); sigprocmask( SIG_BLOCK, &sig_mask, 0 );#else sigblock( sigmask( SIGPIPE ) );#endif connection_socket = new AcceptSocket( 0, INTERPRETER_DEFAULT_PORT ); mark_close_on_exec( connection_socket->FD() ); selector = new Selector; selector->AddSelectee( new AcceptSelectee( this, connection_socket ) ); selector->AddTimer( new ProbeTimer( &daemons, this ) ); connection_host = local_host_name(); connection_port = new char[32]; sprintf( connection_port, "%d", connection_socket->Port() ); static const char tag_fmt[] = "*tag-%s.%d*"; int n = strlen( tag_fmt ) + strlen( connection_host ) + /* slop */ 32; interpreter_tag = new char[n]; sprintf( interpreter_tag, tag_fmt, connection_host, int( getpid() ) ); monitor_task = 0; last_notification = 0; last_whenever_executed = 0; num_active_processes = 0; verbose = 0; // Create the "system" global variable. system_agent = new UserAgent( this ); Value* system_val = system_agent->AgentRecord(); Expr* system_expr = InstallID( strdup( "system" ), GLOBAL_SCOPE ); system_expr->Assign( system_val ); system_val->SetField( "version", new Value( GLISH_VERSION ) ); // Create "script" global. script_client = new ScriptClient( argc, argv ); Expr* script_expr = InstallID( strdup( "script" ), GLOBAL_SCOPE ); if ( script_client->HasSequencerConnection() ) { // Set up script agent to deal with incoming and outgoing // events. ScriptAgent* script_agent = new ScriptAgent( this, script_client ); script_client->SetInterface( selector, script_agent ); script_expr->Assign( script_agent->AgentRecord() ); system_val->SetField( "is_script_client", new Value( glish_true ) ); // Include ourselves as an active process; otherwise // we'll exit once our child processes are gone. ++num_active_processes; } else { script_expr->Assign( new Value( glish_false ) ); system_val->SetField( "is_script_client", new Value( glish_false ) ); } name = argv[0]; for ( ++argv, --argc; argc > 0; ++argv, --argc ) { if ( ! strcmp( argv[0], "-v" ) ) ++verbose; else if ( strchr( argv[0], '=' ) ) putenv( argv[0] ); else break; } MakeEnvGlobal(); BuildSuspendList(); char* monitor_client_name = getenv( "glish_monitor" ); if ( monitor_client_name ) ActivateMonitor( monitor_client_name ); Parse( glish_init ); const char* glish_rc; if ( (glish_rc = getenv( "GLISHRC" )) ) Parse( glish_rc ); else { FILE* glish_rc_file = fopen( GLISH_RC_FILE, "r" ); const char* home; if ( glish_rc_file ) { fclose( glish_rc_file ); Parse( GLISH_RC_FILE ); } else if ( (home = getenv( "HOME" )) ) { char glish_rc_filename[256]; sprintf( glish_rc_filename, "%s/%s", home, GLISH_RC_FILE ); if ( (glish_rc_file = fopen( glish_rc_filename, "r")) ) { fclose( glish_rc_file ); Parse( glish_rc_filename ); } } } int do_interactive = 1; if ( argc > 0 && strcmp( argv[0], "--" ) ) { // We have a file to parse. Parse( argv[0] ); do_interactive = 0; ++argv, --argc; } MakeArgvGlobal( argv, argc ); if ( do_interactive ) Parse( stdin ); }Sequencer::~Sequencer() { delete script_client; delete selector; delete connection_socket; delete connection_port; delete interpreter_tag; }void Sequencer::AddBuiltIn( BuiltIn* built_in ) { Expr* id = InstallID( strdup( built_in->Name() ), GLOBAL_SCOPE ); id->Assign( new Value( built_in ) ); }void Sequencer::QueueNotification( Notification* n ) { if ( verbose > 1 ) message->Report( "queueing", n ); notification_queue.EnQueue( n ); }void Sequencer::PushScope() { scopes.append( new expr_dict ); }int Sequencer::PopScope() { int top_scope_pos = scopes.length() - 1; if ( top_scope_pos < 0 ) fatal->Report( "scope underflow in Sequencer::PopScope" ); expr_dict* top_scope = scopes[top_scope_pos]; int frame_size = top_scope->Length(); scopes.remove( top_scope ); delete top_scope; return frame_size; }Expr* Sequencer::InstallID( char* id, scope_type scope ) { int scope_index; if ( scope == LOCAL_SCOPE ) scope_index = scopes.length() - 1; else scope_index = 0; int frame_offset = scopes[scope_index]->Length(); Expr* result = new VarExpr( id, scope, frame_offset, this ); scopes[scope_index]->Insert( id, result ); if ( scope == GLOBAL_SCOPE ) global_frame.append( 0 ); return result; }Expr* Sequencer::LookupID( char* id, scope_type scope, int do_install ) { int scope_index; if ( scope == LOCAL_SCOPE ) scope_index = scopes.length() - 1; else scope_index = 0; Expr* result = (*scopes[scope_index])[id]; if ( ! result && do_install ) { if ( scope == LOCAL_SCOPE ) return LookupID( id, GLOBAL_SCOPE ); else return InstallID( id, GLOBAL_SCOPE ); } delete id; return result; }void Sequencer::PushFrame( Frame* new_frame ) { local_frames.append( new_frame ); }Frame* Sequencer::PopFrame() { int top_frame = local_frames.length() - 1; if ( top_frame < 0 ) fatal->Report( "local frame stack underflow in Sequencer::PopFrame" ); return local_frames.remove_nth( top_frame );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -