Home | History | Annotate | Download | only in posix
      1 /* Copyright 2016 The TensorFlow Authors. All Rights Reserved.
      2 
      3 Licensed under the Apache License, Version 2.0 (the "License");
      4 you may not use this file except in compliance with the License.
      5 You may obtain a copy of the License at
      6 
      7     http://www.apache.org/licenses/LICENSE-2.0
      8 
      9 Unless required by applicable law or agreed to in writing, software
     10 distributed under the License is distributed on an "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 See the License for the specific language governing permissions and
     13 limitations under the License.
     14 ==============================================================================*/
     15 
     16 #ifndef TENSORFLOW_CORE_PLATFORM_POSIX_SUBPROCESS_H_
     17 #define TENSORFLOW_CORE_PLATFORM_POSIX_SUBPROCESS_H_
     18 
     19 #include <errno.h>
     20 #include <unistd.h>
     21 
     22 #include <string>
     23 #include <vector>
     24 
     25 #include "tensorflow/core/platform/macros.h"
     26 #include "tensorflow/core/platform/mutex.h"
     27 #include "tensorflow/core/platform/types.h"
     28 
     29 namespace tensorflow {
     30 
     31 class SubProcess {
     32  public:
     33   // SubProcess()
     34   //    nfds: The number of file descriptors to use.
     35   explicit SubProcess(int nfds = 3);
     36 
     37   // Virtual for backwards compatibility; do not create new subclasses.
     38   // It is illegal to delete the SubProcess within its exit callback.
     39   virtual ~SubProcess();
     40 
     41   // SetChannelAction()
     42   //    Set how to handle a channel.  The default action is ACTION_CLOSE.
     43   //    The action is set for all subsequent processes, until SetChannel()
     44   //    is called again.
     45   //
     46   //    SetChannel may not be called while the process is running.
     47   //
     48   //    chan: Which channel this applies to.
     49   //    action: What to do with the channel.
     50   // Virtual for backwards compatibility; do not create new subclasses.
     51   virtual void SetChannelAction(Channel chan, ChannelAction action);
     52 
     53   // SetProgram()
     54   //    Set up a program and argument list for execution, with the full
     55   //    "raw" argument list passed as a vector of strings.  argv[0]
     56   //    should be the program name, just as in execv().
     57   //
     58   //    file: The file containing the program.  This must be an absolute path
     59   //          name - $PATH is not searched.
     60   //    argv: The argument list.
     61   virtual void SetProgram(const string& file, const std::vector<string>& argv);
     62 
     63   // Start()
     64   //    Run the command that was previously set up with SetProgram().
     65   //    The following are fatal programming errors:
     66   //       * Attempting to start when a process is already running.
     67   //       * Attempting to start without first setting the command.
     68   //    Note, however, that Start() does not try to validate that the binary
     69   //    does anything reasonable (e.g. exists or can execute); as such, you can
     70   //    specify a non-existent binary and Start() will still return true.  You
     71   //    will get a failure from the process, but only after Start() returns.
     72   //
     73   //    Return true normally, or false if the program couldn't be started
     74   //    because of some error.
     75   // Virtual for backwards compatibility; do not create new subclasses.
     76   virtual bool Start();
     77 
     78   // Kill()
     79   //    Send the given signal to the process.
     80   //    Return true normally, or false if we couldn't send the signal - likely
     81   //    because the process doesn't exist.
     82   virtual bool Kill(int signal);
     83 
     84   // Wait()
     85   //    Block until the process exits.
     86   //    Return true normally, or false if the process wasn't running.
     87   virtual bool Wait();
     88 
     89   // Communicate()
     90   //    Read from stdout and stderr and writes to stdin until all pipes have
     91   //    closed, then waits for the process to exit.
     92   //    Note: Do NOT call Wait() after calling Communicate as it will always
     93   //     fail, since Communicate calls Wait() internally.
     94   //    'stdin_input', 'stdout_output', and 'stderr_output' may be NULL.
     95   //    If this process is not configured to send stdout or stderr to pipes,
     96   //     the output strings will not be modified.
     97   //    If this process is not configured to take stdin from a pipe, stdin_input
     98   //     will be ignored.
     99   //    Returns the command's exit status.
    100   virtual int Communicate(const string* stdin_input, string* stdout_output,
    101                           string* stderr_output);
    102 
    103  private:
    104   static const int kNFds = 3;
    105   static bool chan_valid(int chan) { return ((chan >= 0) && (chan < kNFds)); }
    106   static bool retry(int e) {
    107     return ((e == EINTR) || (e == EAGAIN) || (e == EWOULDBLOCK));
    108   }
    109   void FreeArgs() EXCLUSIVE_LOCKS_REQUIRED(data_mu_);
    110   void ClosePipes() EXCLUSIVE_LOCKS_REQUIRED(data_mu_);
    111   bool WaitInternal(int* status);
    112 
    113   // The separation between proc_mu_ and data_mu_ mutexes allows Kill() to be
    114   // called by a thread while another thread is inside Wait() or Communicate().
    115   mutable mutex proc_mu_;
    116   bool running_ GUARDED_BY(proc_mu_);
    117   pid_t pid_ GUARDED_BY(proc_mu_);
    118 
    119   mutable mutex data_mu_ ACQUIRED_AFTER(proc_mu_);
    120   char* exec_path_ GUARDED_BY(data_mu_);
    121   char** exec_argv_ GUARDED_BY(data_mu_);
    122   ChannelAction action_[kNFds] GUARDED_BY(data_mu_);
    123   int parent_pipe_[kNFds] GUARDED_BY(data_mu_);
    124   int child_pipe_[kNFds] GUARDED_BY(data_mu_);
    125 
    126   TF_DISALLOW_COPY_AND_ASSIGN(SubProcess);
    127 };
    128 
    129 }  // namespace tensorflow
    130 
    131 #endif  // TENSORFLOW_CORE_PLATFORM_POSIX_SUBPROCESS_H_
    132