Starting Programs - program_startup

Cogent Tools Demo and Tutorials: Version 4.0
Prev | Chapter 6. Common Functions (in both `gtksimple.g` and `phsimple.g`) | Next

# 6.2. Starting Programs - `program_startup`

This function is called by the `main` function of both `gtksimple.g` and `phsimple.g`. It handles the necessary start-up tasks for those programs. For arguments, it takes the program's process name and queue name as strings (`proc_name` and `queue_name`), and a function that starts the program's main window (`win_fn`).

| This function is an adaptation of the common function `program_startup` explained in Tutorial Two.

       /*--------------------------------------------------------------------
        * Function:    program_startup
        * Returns:     t or nil
        * Description: Starts any necessary Cogent software and the main window.
        *              Called by the main() function.
        *------------------------------------------------------------------*/
       function program_startup (proc_name, queue_name, win_fn)
       {
         local window, tsk;

The first task is to call the `start_qnserves` function to start the Cogent tools that support interprocess communication: qserve and nserve.

         /* See if qserve and nserve are running. If not, start them. */
         start_qnserves("qserve", "qserve");
         start_qnserves("nserve", "sc/nserve");

Once qserve and nserve are running, the we can initiate interprocess communication (IPC) using the Gamma `init_ipc` function:

         /* Start interprocess communication. */
         if (init_ipc(proc_name, queue_name, "toolsdemo") == nil)
           error("Could not initialize IPC.");

For interprocess communication, each program needs a name to be used by nserve (`proc_name`); and a queue name to be used by qserve (`queue_name`), which are passed in as function arguments. The program also is assigned a domain (`toolsdemo`), to keep the demo program and its datahub points separate from other Cogent processes that may be running on the system.

Now that IPC is running, we can start the Cascade DataHub.

         /* See if a DataHub is running in the toolsdemo domain.
            If not, start it and a DataHub Viewer. */
         if ((tsk = locate_task ("/dh/toolsdemo", t)) == nil)
             system("datahub -d toolsdemo");
         else
           close_task (tsk);

The Gamma `locate_task` function queries nserve to see if a datahub is running in the `toolsdemo` domain. If there is a datahub in that domain, the program uses it and closes the task with the Gamma `close_task` function. If no datahub is running, the program starts one using the Gamma `system` function.

We next use the Gamma functions `fork` to spawn child processes, and `exec` to start the DataHub Viewer and PID Emulator. The Gamma `princ` function is used to print messages to the console.

         if ((pid_dhview = fork()) == 0)
           {
             /* The child process is the DataHub Viewer. */
             exec ("dhview", "-d", "toolsdemo");
             /* In case the above exec commands fails, the following will be
              * called, and it's virtually guaranteed not to fail.  Thus in
              * any circumstance a child process gets created.*/
             exec("/bin/true");
           }
         princ("The process ID of the DataHub Viewer is: ", pid_dhview, "\n");

         /* Make sure the PID Emulator is not already running. */
         if ((tsk = locate_task ("emul", t)) != nil)
           {
             send(tsk, #exit_program(0));
             close_task (tsk);
           }

         /* Start the PID Emulator. */
         if ((pid_emul = fork()) == 0)
           {
             /* The child process is the PID Emulator. */
             exec ("gamma", "emul");
             exec("/bin/true");
           }
         princ("The process ID of the PID Emulator is: ", pid_emul, "\n");

To terminate the PID Emulator and DataHub Viewer when the program exits, we use the Gamma functions `atexit` and `kill`.

         /* Kill child processes when this program exits. */
         atexit(`kill(pid_dhview, SIGINT));
         atexit(`kill(pid_emul, SIGINT));

The Monitor needs to register some point names with the Cascade DataHub on startup, using the Gamma `register_point` function.

         /* Create and register some points with the datahub. */
         SP_001 = register_point (#SP_001);
         PV_001 = register_point (#PV_001);
         MV_001 = register_point (#MV_001);
         AUTO_001 = register_point (#AUTO_001);
         FREQ_001 = register_point (#FREQ_001);
         PID1_Kp = register_point (#PID1_Kp);
         PID1_Ki = register_point (#PID1_Ki);
         PID1_Kd = register_point (#PID1_Kd);
         PROP_001 = register_point (#PROP_001);
         INT_001 = register_point (#INT_001);

Finally, we create the main window for the program. The GTK version of this program needs a `destroy` signal, but Photon does not, so the final line in this function only appears in `gtksimple.g`.

         /* Create the main window, and put in a destructor function for GTK */
         window = eval(win_fn);
         window.signal ("destroy", #exit_program(0));
       }

Prev | Home | Next
Common Functions (in both `gtksimple.g` and `phsimple.g`) | Up | GTK Functions (in `gtksimple.g`)

Copyright 1995-2002 by Cogent Real-Time Systems, Inc.