Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

Process.cc

Go to the documentation of this file.
00001 /*
00002  * Process.cc
00003  *
00004  * Smalltalk like class library for C++
00005  * Process wrapper.
00006  *
00007  * Copyright (c) 2004 Milan Cermak
00008  */
00009 /*
00010  * This library is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU Lesser General Public
00012  * License as published by the Free Software Foundation; either
00013  * version 2.1 of the License, or (at your option) any later version.
00014  *
00015  * This library is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * Lesser General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU Lesser General Public
00021  * License along with this library; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  */
00024 #include <stdio.h>
00025 #include <unistd.h>
00026 #include <stdlib.h>
00027 #include <signal.h>
00028 #include <sys/types.h>
00029 #include <sys/wait.h>
00030 
00031 #include <stlib/os/Process.h>
00032 #include <stlib/Array.h>
00033 #include <stlib/FileAccessor.h>
00034 #include <stlib/Iterator.h>
00035 #include <stlib/Set.h>
00036 #include <stlib/String.h>
00037 
00038 using namespace OS;
00039 
00040 bool Process::has_handler = false;
00041 Set Process::processes(5);         // Process container
00042 
00043 Process::Process(void)
00044 {
00045     finalizeProcesses();
00046     _receiver = nil;
00047     _arguments = nil;
00048     // Nastavime priznak beziciho vlakna
00049     runningProcess = false;
00050     process_id = 0;
00051     _status = 0;
00052 }
00053 
00054 Process::Process(Callback<void> *receiver, Array *args)
00055 {
00056     finalizeProcesses();
00057     // Nastavime vykonnou funkci
00058     _receiver = receiver;
00059     _arguments = args;
00060     // Nastavime priznak beziciho vlakna
00061     runningProcess = false;
00062     process_id = 0;
00063     _status = 0;
00064 }
00065 
00066 Process::~Process(void)
00067 {
00068 //    terminate();
00069 }
00070 
00071 Process *Process::fork(Callback<void> *receiver)
00072 {
00073     Process *process = new Process(receiver);
00074     process->run();
00075     return process;
00076 }
00077 
00078 Process *Process::fork(Callback<void> *receiver, Array *args)
00079 {
00080     Process *process = new Process(receiver, args);
00081     process->run();
00082     return process;
00083 }
00084 
00085 Process *Process::forkJob(String *progName, SequenceableCollection *args,
00086                           SequenceableCollection *fds)
00087 {
00088     Callback1<Process,void,Array*> *callback;
00089     Array *funcArgs = Array::with(progName, args, fds);
00090     Process *process = new Process;
00091 
00092     callback = new Callback1<Process,void,Array*>(process, &Process::privateExecuteJob);
00093     process->receiver(callback);
00094     process->arguments(funcArgs);
00095     process->run();
00096     return process;
00097 }
00098 
00099 /* Accessing protocol */
00100 void Process::arguments(Array *args)
00101 {
00102     _arguments = args;
00103 }
00104 
00105 void Process::receiver(Callback<void> *obj)
00106 {
00107     _receiver = obj;
00108 }
00109 
00110 int Process::status(void)
00111 {
00112     return _status;
00113 }
00114 
00115 /* Prevezme hodnoty od ukoncenych procesu */
00116 void Process::finalizeProcesses(void)
00117 {
00118     Set *temp = (Set *) processes.copy();
00119     for (Iterator* i = temp->iterator(); !i->finished(); i->next()) {
00120         Process *p = (Process *) i->value();
00121         if (!p->isRunning())
00122             p->finalize();
00123     }
00124     delete temp;
00125 }
00126 
00127 // obnovi beh procesu
00128 void Process::resume()
00129 {
00130     if (runningProcess == false) {  // vlakno dosud nebylo vytvoreno
00131         // zadna akce
00132         return;
00133     }
00134     kill(process_id, SIGCONT);
00135 }
00136 
00137 // pozastavi beh procesu
00138 void Process::suspend()
00139 {
00140     if (runningProcess == false) {  // vlakno dosud nebylo vytvoreno
00141         // zadna akce
00142         return;
00143     }
00144     kill(process_id, SIGSTOP);
00145 }
00146 
00147 void Process::run()
00148 {
00149     int pid;
00150     if (_receiver == nil) return;  // Not fully initialized
00151 
00152     if ((pid = ::fork()) == 0) {
00153         /* I'm child */
00154         runningProcess = true;
00155         _receiver->executeWith(_arguments);
00156         exit(0);
00157     } else {
00158         /* I'm parent */
00159         if (pid == -1) { // fork failed
00160             // Better to raise an Exception here
00161             return;
00162         }
00163         runningProcess = true;
00164         process_id = pid;
00165         processes.add(this);
00166         if (!has_handler) {
00167             struct sigaction handler;
00168             handler.sa_handler = Process::sigchildHandler;
00169             handler.sa_flags = SA_NOCLDSTOP;
00170             sigaction(SIGCHLD, &handler, NULL);
00171             has_handler = true;
00172         }
00173     }
00174 }
00175 
00176 void Process::finalize(void)
00177 {
00178     processes.remove(this);
00179 }
00180 
00181 void Process::terminate(void)
00182 {
00183     // zruseni vlakna
00184     if (runningProcess != false) {
00185         kill(process_id, SIGTERM);
00186         // Pockame az vlakno dobehne a odchytime navratovou hodnotu
00187         finalize();
00188     }
00189 }
00190 
00191 void Process::yield(void)
00192 {
00193     /* nothing
00194        - there is no way to force another process to leave the processor */
00195 }
00196 
00197 /* Testing protocol */
00198 bool Process::isRunning(void)
00199 {
00200     return runningProcess;
00201 }
00202 
00203 /* Private protocol */
00204 void Process::childSignaled(void)
00205 {
00206     int pid;
00207     pid = waitpid(process_id, &_status, WNOHANG);
00208     if (pid > 0) {
00209         runningProcess = false;
00210         finalize();
00211     }
00212 }
00213 
00214 void Process::privateExecuteJob(Array *args)
00215 {
00216     String *progName = (String *) args->at(0);
00217     SequenceableCollection *progArgs = (SequenceableCollection *) args->at(1);
00218     SequenceableCollection *fds = (SequenceableCollection *) args->at(2);
00219 
00220     char *file = progName->asCString();
00221     char *fileArgs[progArgs->size() + 2];
00222     fileArgs[0] = file;
00223     for (int i = 0; i < progArgs->size(); i++)
00224         fileArgs[i+1] = dynamic_cast<String *>(progArgs->at(i))->asCString();
00225     fileArgs[progArgs->size() + 1] = NULL;
00226     /* file descriptors assignment */
00227     if (fds != nil) {
00228         FileAccessor *fd = dynamic_cast<FileAccessor *>(fds->at(0));
00229         if (fd != nil) {
00230             close(0);   // stdin
00231             fd->changeDescriptorTo(0);
00232         }
00233         fd = dynamic_cast<FileAccessor *>(fds->at(1));
00234         if (fd != nil) {
00235             close(1);   // stdout
00236             fd->changeDescriptorTo(1);
00237         }
00238         fd = dynamic_cast<FileAccessor *>(fds->at(2));
00239         if (fd != nil) {
00240             close(2);   // stderr
00241             fd->changeDescriptorTo(2);
00242         }
00243     }
00244     execvp(file, fileArgs);
00245 }
00246 
00247 void Process::sigchildHandler(int signum)
00248 {
00249     Set *temp = (Set *) processes.copy();
00250     for (Iterator* i = temp->iterator(); !i->finished(); i->next()) {
00251         Process *p = (Process *) i->value();
00252         p->childSignaled();
00253     }
00254     delete temp;
00255 }

Generated on Mon Nov 27 09:47:55 2006 for Smalltalk like C++ Class Library by  doxygen 1.4.2