logo
Free, unlimited AI code reviews that run on commit
git-lrc git-lrc GitHub Install Now We'd appreciate a star git-lrc - Free, unlimited AI code reviews that run on commit | Product Hunt git-lrc - Free, unlimited AI code reviews that run on commit | Product Hunt

FBB::Fork - Implements fork(2) using the Template Design Pattern

Author

       Frank B. Brokken (f.b.brokken@rug.nl).

libbobcat-dev_6.07.01                               2005-2025                                 FBB::Fork(3bobcat)

Bobcat

       Bobcat is an acronym of `Brokken’s Own Base Classes And Templates’.

Bobcat Project Files

       o      https://fbb-git.gitlab.io/bobcat/: gitlab project page;

       Debian Bobcat project files:

       o      libbobcat6: debian package containing the shared library, changelog and copyright note;

       o      libbobcat-dev: debian package containing the static library, headers, manual pages, and  developer
              info;

Bugs

       None Reported.

Constructors

       Only the default constructor is available.

Description

FBB::Fork  objects  may  be  used  to implement the fork(2) call as part of the Template Algorithm Design
       Pattern. The class was designed as a virtual base class for classes implementing the essential  parts  of
       the  forking  process.  The  class  is  a  virtual base class. Derived classes must implement the members
       childProcess and parentProcess as part of the `Template Method Design Pattern’ (see Gamma etal., 1995).

       Terminating child processes send SIGCHLD signals to their parents. The C  library  offers  the  following
       macros  to  analyze the status values received by the parent process using a wait(2) or waitpid(2) system
       call:

       o      intWIFEXITED(intstatus):
              This macro returns a nonzero value if  the  child  process  terminated  normally  with  `exit’  or
              `_exit’.

       o      intWEXITSTATUS(intstatus):
              If  `WIFEXITED’  is  true  of `status’, this macro returns the low-order 8 bits of the exit status
              value from the child process.

       o      intWIFSIGNALED(intstatus):
              This macro returns a nonzero value if the child process terminated because it  received  a  signal
              that was not handled.

       o      intWTERMSIG(intstatus):
              If  `WIFSIGNALED’  is  true  of  `status’, this macro returns the signal number of the signal that
              terminated the child process.

       o      intWCOREDUMP(intstatus):
              This macro returns a nonzero value if the child process terminated and produced a core dump.

       o      intWIFSTOPPED(intstatus):
              This macro returns a nonzero value if the child process is stopped.

       o      intWSTOPSIG(intstatus):
              If `WIFSTOPPED’ is true of `status’, this macro returns the  signal  number  of  the  signal  that
              caused the child process to stop.

Destructor

       o      virtual~Fork():
              Derived classes may define their own destructor, which is  called  when  the  Fork  destructor  is
              activated.

Examples

       #include <iostream>
       #include <unistd.h>

       #include <bobcat/fork>

       using namespace std;
       using namespace FBB;

       class Background: public Fork
       {
           public:
               void childProcess()     override;
               void parentProcess()    override;
       };

       void Background::childProcess()
       {
           for (int idx = 0; idx < 3; ++idx)
           {
               cout << "Hello world # " << idx << endl;
               sleep(1);
           }
           throw 0;    // caught in main()
       }

       void Background::parentProcess()
       {
           cout << "Waiting for the child process to end...\n"
                   "The child returns value " << waitForChild() << endl;
       }

       int main()
       try
       {
           Background bg;

           bg.fork();
           cout << "This is from the parent\n";
       }
       catch(int x)
       {
           cout << "The child terminates with: " << x << endl;
           return x;
       }

       Here’s a more extensive example:

       #include <iostream>
       #include <string>

       #include <signal.h>
       #include <unistd.h>

       #include <sys/types.h>

       #include <bobcat/pipe>
       #include <bobcat/ofdstream>
       #include <bobcat/ifdstream>
       #include <bobcat/process>
       #include <bobcat/fork>

       class ChildIO: public FBB::Fork
       {
           FBB::Pipe childInput;   // child reads this
           FBB::Pipe childOutput;   // child writes this

           public:
               void childRedirections()    override;
               void childProcess()         override;
               void parentProcess()        override;
       };

       using namespace std;
       using namespace FBB;

       void ChildIO::childRedirections()
       {
           childInput.readFrom(Redirector::STDIN);
           childOutput.writtenBy(Redirector::STDOUT);
       }

       void ChildIO::childProcess()
       {
               // The /bin/cat program replaces the
               // child process started by Fork::fork()
           Process process(Process::DIRECT, "/bin/cat");
           process.start();

           // this point is never reached
       }

       void ChildIO::parentProcess()
       {
               // Set up the parent’s sides of the pipes
           IFdStream fromChild(childOutput.readOnly());
           OFdStream toChild(childInput.writeOnly());

               // write lines to the child, read its output
           string line;
           while (true)
           {
               cout << "? ";
               line.clear();
               getline(cin, line);

               if (line.empty())
               {
                   kill(pid(), SIGTERM);
                   break;
               }

               toChild << line << endl;

               getline(fromChild, line);
               cout << "Got: " << line << endl;
           }
           cout << "The child returns value " << waitForChild() << endl;
       }

       int main()
       try
       {
           ChildIO io;

           io.fork();

           return 0;
       }
       catch(exception const &exc)
       {
           cerr << "Exception: " << exc.what() << endl;
       }
       catch(int x)
       {
           cout << "The child terminates with: " << x << endl;
           return x;
       }

Files

bobcat/fork - defines the class interface

Inherits From

       -

Member Functions

       o      voidfork():
              Performs  the  actual  forking. It is implemented in such a way that the corresponding parent- and
              child- processes are activated from virtual members of Fork. If the forking  operation  fails,  an
              FBB::Exception exception is thrown.

Name

       FBB::Fork - Implements fork(2) using the Template Design Pattern

Namespace

FBB
       All  constructors,  members,  operators  and manipulators, mentioned in this man-page, are defined in the
       namespace FBB.

Private (Virtual) Member Functions

       o      virtualvoidchildProcess()=0:
              This  member  must be implemented by derived classes. It defines the actions that are performed by
              the child process, following  the  fork(2)  system  call.  Just  before  childProcess  is  called,
              childRedirections  (see below) has been executed. The childProcess() function should terminate the
              child process. A good way to do this is to throw an exception which is caught by main()’s function
              try block. Terminating a process using exit(2) is deprecated in C++.

       o      virtualvoidchildRedirections():
              This function may be redefined in derived classes to set up the redirections that are necessary to
              communicate with the parent process. See also the classes redirector(3bobcat)  and  pipe(3bobcat).
              By default, childRedirections does nothing.

       o      virtualvoidparentProcess()=0:
              This  member  must be implemented by derived classes. It defines the actions that are performed by
              the parent process, following the fork(2)  system  call.  Just  before  parentProcess  is  called,
              parentRedirections (see below) has been executed.

              When  deriving classes from Fork their parentProcess implementation preferably handles all actions
              to perform by the parent process. If the child process remains  active  when  the  parent  process
              decides  that  the  program  has  performed  its  duties (e.g., the child process is replaced by a
              program started by an exec.. function, continuously producing output, interpreted  by  the  parent
              process)  then  the  parent  process  can call endChild to end the child process before ending the
              parentProcess function.

       o      virtualvoidparentRedirections():
              This function may be redefined in derived classes to set up the redirections that are necessary to
              communicate with, e.g., the parent. See, e.g., the classes redirector(3bobcat) and  pipe(3bobcat).
              By default, parentRedirections does nothing.

Protected Member Functions

       o      intendChild()const:
              This  member  may  be called by parentProcess to end the child process. To end the child process a
              SIGTERM is sent to the child process, followed by a SIGKILL (cf. signal(7)). If the child  process
              has  already  ended then the child process’s exit value is returned, otherwise the child process’s
              end is forced (by calling kill) and -2 is returned.  This  member  also  calls  waitForChild  (see
              below).

       o      pid_tpid()const:
              Returns  the child’s process id in the parent’s code (i.e., in the parent-members below), and 0 in
              the child’s code (i.e., in the child-members below). The pid member returns -1 when called  before
              the member fork has been called.

       o      voidprepareDaemon()const:
              Prepares  for  a  daemon  childprocess.  This function may (should) be called from childProcess to
              ensure that the child process changes its current working directory to  the  root  (/)  directory,
              thus  freeing  up mount points; that the child process starts a new session/process group to allow
              the parent (group leader) to kill all its processes without terminating the daemon; and makes sure
              that the child process closes and reopens the standard streams by associating them with  /dev/null
              to  prevent  ghost  input  and  output  actions  from  interfering  with  the daemon’s actions. An
              FBB::Exception is thrown if changing directory to the root directory fails.

       o      voidprepareDaemon(std::stringconst&out,std::stringconst&err,mode_tmode=0600)const:
              Prepares for a daemon childprocess like the previous member function, but  allows  redirection  of
              the  standard  output  (out)  and  standard error (err) streams to files. Specify empty strings to
              redirect these streams to /dev/null. With non-empty strings the  specified  files  are  opened  in
              append-mode (and created if not yet existing), by default using mode 0600 (read/write mode for the
              user  only).  An  FBB::Exception is thrown if changing directory to the root directory or if using
              the specified s fails.

       o      intwaitForChild()const:
              This member may be called by parentProcess to wait for the completion of  the  child-process.  The
              return  value  (exit-code)  of  the child process is returned as a value between 0 and 255. If the
              child process terminates before the completion of the parent process, then waitForChild should  be
              called  to  prevent zombies from occurring. Alternatively, the parent process may terminate (e.g.,
              using exit(2)) while the child process is still alive. This is the normal way to create  a  daemon
              process.

See Also

bobcat(7),  cerrextractor(3bobcat), cininserter(3bobcat), coutextractor(3bobcat), exec(3), exec(3bobcat),
       fork(2), kill(2), pipe(3bobcat), redirector(3bobcat), stdextractor(3bobcat), wait(2), waitpid(2).

Synopsis

#include<bobcat/fork>
       Linking option: -lbobcat

See Also