Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(487)

Side by Side Diff: subprocess.cc

Issue 4690006: AU: Execute postinst asynchronously so that the D-Bus service is not blocked. (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/update_engine.git@master
Patch Set: address review comments Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « subprocess.h ('k') | subprocess_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium OS Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "update_engine/subprocess.h" 5 #include "update_engine/subprocess.h"
6 #include <stdlib.h> 6 #include <stdlib.h>
7 #include <string.h> 7 #include <string.h>
8 #include <string> 8 #include <string>
9 #include <unistd.h> 9 #include <unistd.h>
10 #include <vector> 10 #include <vector>
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/scoped_ptr.h" 12 #include "base/scoped_ptr.h"
13 #include "base/string_util.h" 13 #include "base/string_util.h"
14 14
15 using std::string; 15 using std::string;
16 using std::tr1::shared_ptr;
16 using std::vector; 17 using std::vector;
17 18
18 namespace chromeos_update_engine { 19 namespace chromeos_update_engine {
19 20
20 void Subprocess::GChildExitedCallback(GPid pid, gint status, gpointer data) { 21 void Subprocess::GChildExitedCallback(GPid pid, gint status, gpointer data) {
21 COMPILE_ASSERT(sizeof(guint) == sizeof(uint32_t), 22 SubprocessRecord* record = reinterpret_cast<SubprocessRecord*>(data);
22 guint_uint32_size_mismatch); 23
23 guint* tag = reinterpret_cast<guint*>(data); 24 // Make sure we read any remaining process output. Then close the pipe.
24 const SubprocessCallbackRecord& record = Get().callback_records_[*tag]; 25 GStdoutWatchCallback(record->gioout, G_IO_IN, &record->stdout);
25 if (record.callback) 26 int fd = g_io_channel_unix_get_fd(record->gioout);
26 record.callback(status, record.callback_data); 27 g_source_remove(record->gioout_tag);
28 g_io_channel_unref(record->gioout);
29 close(fd);
30
27 g_spawn_close_pid(pid); 31 g_spawn_close_pid(pid);
28 Get().callback_records_.erase(*tag); 32 if (status) {
29 delete tag; 33 LOG(INFO) << "Subprocess status: " << status;
34 }
35 if (!record->stdout.empty()) {
36 LOG(INFO) << "Subprocess output:\n" << record->stdout;
37 }
38 if (record->callback) {
39 record->callback(status, record->stdout, record->callback_data);
40 }
41 Get().subprocess_records_.erase(record->tag);
30 } 42 }
31 43
32 void Subprocess::GRedirectStderrToStdout(gpointer user_data) { 44 void Subprocess::GRedirectStderrToStdout(gpointer user_data) {
33 dup2(1, 2); 45 dup2(1, 2);
34 } 46 }
35 47
48 gboolean Subprocess::GStdoutWatchCallback(GIOChannel* source,
49 GIOCondition condition,
50 gpointer data) {
51 string* stdout = reinterpret_cast<string*>(data);
52 char buf[1024];
53 gsize bytes_read;
54 while (g_io_channel_read_chars(source,
55 buf,
56 arraysize(buf),
57 &bytes_read,
58 NULL) == G_IO_STATUS_NORMAL &&
59 bytes_read > 0) {
60 stdout->append(buf, bytes_read);
61 }
62 return TRUE; // Keep the callback source. It's freed in GChilExitedCallback.
63 }
64
36 namespace { 65 namespace {
37 void FreeArgv(char** argv) { 66 void FreeArgv(char** argv) {
38 for (int i = 0; argv[i]; i++) { 67 for (int i = 0; argv[i]; i++) {
39 free(argv[i]); 68 free(argv[i]);
40 argv[i] = NULL; 69 argv[i] = NULL;
41 } 70 }
42 } 71 }
43 72
44 void FreeArgvInError(char** argv) { 73 void FreeArgvInError(char** argv) {
45 FreeArgv(argv); 74 FreeArgv(argv);
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
99 } 128 }
100 argv[cmd.size()] = NULL; 129 argv[cmd.size()] = NULL;
101 130
102 char** argp = ArgPointer(); 131 char** argp = ArgPointer();
103 if (!argp) { 132 if (!argp) {
104 FreeArgvInError(argv.get()); // NULL in argv[i] terminates argv. 133 FreeArgvInError(argv.get()); // NULL in argv[i] terminates argv.
105 return 0; 134 return 0;
106 } 135 }
107 ScopedFreeArgPointer argp_free(argp); 136 ScopedFreeArgPointer argp_free(argp);
108 137
109 SubprocessCallbackRecord callback_record; 138 shared_ptr<SubprocessRecord> record(new SubprocessRecord);
110 callback_record.callback = callback; 139 record->callback = callback;
111 callback_record.callback_data = p; 140 record->callback_data = p;
112 141 gint stdout_fd = -1;
113 bool success = g_spawn_async(NULL, // working directory 142 bool success = g_spawn_async_with_pipes(
114 argv.get(), 143 NULL, // working directory
115 argp, 144 argv.get(),
116 G_SPAWN_DO_NOT_REAP_CHILD, // flags 145 argp,
117 NULL, // child setup function 146 G_SPAWN_DO_NOT_REAP_CHILD, // flags
118 NULL, // child setup data pointer 147 GRedirectStderrToStdout, // child setup function
119 &child_pid, 148 NULL, // child setup data pointer
120 &err); 149 &child_pid,
150 NULL,
151 &stdout_fd,
152 NULL,
153 &err);
121 FreeArgv(argv.get()); 154 FreeArgv(argv.get());
122 if (!success) { 155 if (!success) {
123 LOG(ERROR) << "g_spawn_async failed"; 156 LOG(ERROR) << "g_spawn_async failed";
124 return 0; 157 return 0;
125 } 158 }
126 guint* tag = new guint; 159 record->tag =
127 *tag = g_child_watch_add(child_pid, GChildExitedCallback, tag); 160 g_child_watch_add(child_pid, GChildExitedCallback, record.get());
128 callback_records_[*tag] = callback_record; 161 subprocess_records_[record->tag] = record;
129 return *tag; 162
163 // Capture the subprocess output.
164 record->gioout = g_io_channel_unix_new(stdout_fd);
165 g_io_channel_set_encoding(record->gioout, NULL, NULL);
166 LOG_IF(WARNING,
167 g_io_channel_set_flags(record->gioout, G_IO_FLAG_NONBLOCK, NULL) !=
168 G_IO_STATUS_NORMAL) << "Unable to set non-blocking I/O mode.";
169 record->gioout_tag = g_io_add_watch(
170 record->gioout,
171 static_cast<GIOCondition>(G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP),
172 GStdoutWatchCallback,
173 &record->stdout);
174 return record->tag;
130 } 175 }
131 176
132 void Subprocess::CancelExec(uint32_t tag) { 177 void Subprocess::CancelExec(uint32_t tag) {
133 if (callback_records_[tag].callback) { 178 subprocess_records_[tag]->callback = NULL;
134 callback_records_[tag].callback = NULL;
135 }
136 } 179 }
137 180
138 bool Subprocess::SynchronousExecFlags(const std::vector<std::string>& cmd, 181 bool Subprocess::SynchronousExecFlags(const std::vector<std::string>& cmd,
139 int* return_code, 182 int* return_code,
140 GSpawnFlags flags) { 183 GSpawnFlags flags) {
141 GError* err = NULL; 184 GError* err = NULL;
142 scoped_array<char*> argv(new char*[cmd.size() + 1]); 185 scoped_array<char*> argv(new char*[cmd.size() + 1]);
143 for (unsigned int i = 0; i < cmd.size(); i++) { 186 for (unsigned int i = 0; i < cmd.size(); i++) {
144 argv[i] = strdup(cmd[i].c_str()); 187 argv[i] = strdup(cmd[i].c_str());
145 if (!argv[i]) { 188 if (!argv[i]) {
(...skipping 25 matching lines...) Expand all
171 return_code, 214 return_code,
172 &err); 215 &err);
173 FreeArgv(argv.get()); 216 FreeArgv(argv.get());
174 if (err) 217 if (err)
175 LOG(INFO) << "err is: " << err->code << ", " << err->message; 218 LOG(INFO) << "err is: " << err->code << ", " << err->message;
176 if (child_stdout && strlen(child_stdout)) 219 if (child_stdout && strlen(child_stdout))
177 LOG(INFO) << "Subprocess output:\n" << child_stdout; 220 LOG(INFO) << "Subprocess output:\n" << child_stdout;
178 return success; 221 return success;
179 } 222 }
180 223
224 bool Subprocess::SubprocessInFlight() {
225 for (std::map<int, shared_ptr<SubprocessRecord> >::iterator it =
226 subprocess_records_.begin();
227 it != subprocess_records_.end(); ++it) {
228 if (it->second->callback)
229 return true;
230 }
231 return false;
232 }
233
181 Subprocess* Subprocess::subprocess_singleton_ = NULL; 234 Subprocess* Subprocess::subprocess_singleton_ = NULL;
182 235
183 } // namespace chromeos_update_engine 236 } // namespace chromeos_update_engine
OLDNEW
« no previous file with comments | « subprocess.h ('k') | subprocess_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698