root/trunk/whisperlib/common/sync/system.cc

Revision 7, 4.6 kB (checked in by whispercastorg, 2 years ago)

version 0.2.0

Line 
1 // Copyright (c) 2009, Whispersoft s.r.l.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Whispersoft s.r.l. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Cosmin Tudorache
31
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <unistd.h>
35 #include <signal.h>
36 #include "common/sync/system.h"
37 #include "common/base/errno.h"
38
39 namespace process {
40
41 System::System(const char* cmd)
42   : cmd_(cmd),
43     exit_status_(kInvalidExitValue),
44     exit_callback_(NULL),
45     executor_run_callback_(NewPermanentCallback(this, &System::ExecutorRun)),
46     executor_thread_(executor_run_callback_),
47     executor_thread_start_(false, true),
48     executor_thread_stop_(false, true),
49     executor_running_(false) {
50 }
51 System::System(const string& cmd)
52   : cmd_(cmd),
53     exit_status_(kInvalidExitValue),
54     exit_callback_(NULL),
55     executor_run_callback_(NewPermanentCallback(this, &System::ExecutorRun)),
56     executor_thread_(executor_run_callback_),
57     executor_thread_start_(false, true),
58     executor_thread_stop_(false, true),
59     executor_running_(false) {
60 }
61 System::~System() {
62   CHECK(!IsRunning());
63   delete executor_run_callback_;
64   executor_run_callback_ = NULL;
65 }
66
67 bool System::Start() {
68   if ( IsRunning() ) {
69     return false;
70   }
71   executor_thread_start_.Reset();
72   executor_thread_stop_.Reset();
73   executor_running_ = false;
74
75   if ( !executor_thread_.Start() ) {
76     LOG_ERROR << "Failed to start executor thread: "
77               << GetLastSystemErrorDescription();
78     return false;
79   }
80
81   if ( !executor_thread_start_.Wait(5000) ) {
82     LOG_ERROR << "Timeout waiting for executor thread startup";
83     executor_thread_.Kill();
84     executor_thread_start_.Reset();
85     executor_thread_stop_.Reset();
86     executor_running_ = false;
87     return false;
88   }
89   return true;
90 }
91
92 bool System::Wait(uint32 timeout_ms, int* exit_status) {
93   if ( !executor_thread_stop_.Wait(timeout_ms) ) {
94     // Timeout, the process is still running.
95     return false;
96   }
97   *exit_status = exit_status_;
98   return true;
99 }
100
101 void System::SetExitCallback(ExitCallback* exit_callback) {
102   exit_callback_ = exit_callback;
103 }
104
105 bool System::IsRunning() const {
106   return executor_running_;
107 }
108
109 void System::Kill() {
110   LOG_FATAL << "Cannot kill a ::system command";
111 }
112
113 void System::ExecutorRun() {
114   executor_running_ = true;
115   executor_thread_start_.Signal();
116
117   LOG_WARNING << "Executing system command: " << cmd_;
118
119   int result = ::system(cmd_.c_str());
120   if ( result == -1 ) {
121     LOG_ERROR << "System command failed for cmd: " << cmd_ << " error: "
122               << GetLastSystemErrorDescription();
123     exit_status_ = kErrorExitValue;
124   } else {
125     exit_status_ = WEXITSTATUS(result);
126     LOG_WARNING << "System command terminated: exit_status_=" << exit_status_;
127     if (WIFSIGNALED(result) && (WTERMSIG(result) == SIGINT ||
128                                 WTERMSIG(result) == SIGQUIT)) {
129       // A SIGINT or SIGQUIT was received while running the child.
130       // Send ourselves SIGINT.
131       ::kill(::getpid(), SIGINT);
132     }
133     if ( exit_status_ == 127 ) {
134       LOG_WARNING << "System command may have failed with: '/bin/sh' "
135                   << "could not be executed";
136     }
137   }
138
139   if ( exit_callback_ ) {
140     exit_callback_->Run(exit_status_);
141   }
142
143   executor_running_ = false;
144   executor_thread_stop_.Signal();
145 }
146 }
Note: See TracBrowser for help on using the browser.