1 : // Copyright 2013 Google Inc. 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 : #include "syzygy/trace/common/service_util.h"
16 :
17 : #include "base/file_util.h"
18 : #include "sawbuck/common/com_utils.h"
19 :
20 : namespace trace {
21 : namespace common {
22 :
23 : bool AcquireMutex(const base::StringPiece16& mutex_name,
24 E : base::win::ScopedHandle* mutex) {
25 E : DCHECK(mutex != NULL);
26 E : DCHECK(!mutex->IsValid());
27 :
28 E : std::wstring name(mutex_name.begin(), mutex_name.end());
29 E : const wchar_t* name_ptr = name.empty() ? NULL : name.c_str();
30 :
31 E : base::win::ScopedHandle tmp_mutex(::CreateMutex(NULL, FALSE, name_ptr));
32 E : if (!tmp_mutex.IsValid()) {
33 i : DWORD error = ::GetLastError();
34 i : LOG(ERROR) << "Failed to create named mutex: " << com::LogWe(error) << ".";
35 i : return false;
36 : }
37 E : const DWORD kOneSecondInMs = 1000;
38 :
39 E : switch (::WaitForSingleObject(tmp_mutex, kOneSecondInMs)) {
40 : case WAIT_ABANDONED:
41 i : LOG(WARNING) << "Orphaned named mutex found!";
42 : // Fall through...
43 :
44 : case WAIT_OBJECT_0:
45 E : VLOG(1) << "Named mutex acquired.";
46 E : mutex->Set(tmp_mutex.Take());
47 E : return true;
48 :
49 : case WAIT_TIMEOUT:
50 E : LOG(ERROR) << "A synonymous named mutex already exists.";
51 E : break;
52 :
53 : default: {
54 i : DWORD error = ::GetLastError();
55 i : LOG(ERROR) << "Failed to acquire mutex: " << com::LogWe(error) << ".";
56 : break;
57 : }
58 : }
59 E : return false;
60 E : }
61 :
62 : bool InitEvent(const base::StringPiece16& event_name,
63 E : base::win::ScopedHandle* handle) {
64 E : DCHECK(handle != NULL);
65 E : DCHECK(!handle->IsValid());
66 :
67 : // StringPieces aren't guaranteed to be NULL terminated, so we make a copy.
68 E : std::wstring name(event_name.begin(), event_name.end());
69 E : const wchar_t* name_ptr = name.empty() ? NULL : name.c_str();
70 :
71 E : handle->Set(::CreateEvent(NULL, TRUE, FALSE, name_ptr));
72 E : if (!handle->IsValid())
73 i : return false;
74 E : return true;
75 E : }
76 :
77 E : ScopedConsoleCtrlHandler::ScopedConsoleCtrlHandler() : handler_(NULL) {
78 E : }
79 :
80 E : ScopedConsoleCtrlHandler::~ScopedConsoleCtrlHandler() {
81 E : if (handler_ != NULL) {
82 i : ignore_result(::SetConsoleCtrlHandler(handler_, FALSE));
83 i : handler_ = NULL;
84 : }
85 E : }
86 :
87 i : bool ScopedConsoleCtrlHandler::Init(PHANDLER_ROUTINE handler) {
88 i : DCHECK(handler != NULL);
89 i : DCHECK(handler_ == NULL);
90 :
91 i : if (!::SetConsoleCtrlHandler(handler, TRUE)) {
92 i : DWORD err = ::GetLastError();
93 i : LOG(ERROR) << "Failed to register console control handler: "
94 : << com::LogWe(err) << ".";
95 i : return false;
96 : }
97 :
98 i : handler_ = handler;
99 i : return true;
100 i : }
101 :
102 : bool SplitCommandLine(const CommandLine* orig_command_line,
103 : CommandLine* logger_command_line,
104 E : scoped_ptr<CommandLine>* app_command_line) {
105 E : DCHECK(orig_command_line != NULL);
106 E : DCHECK(!orig_command_line->argv().empty());
107 E : DCHECK(logger_command_line != NULL);
108 E : DCHECK(app_command_line != NULL);
109 :
110 : // Copy the initial parts of the command-line, up to and including the
111 : // first non-switch argument (which should be the "action"), into a
112 : // string vector for the logger command line.
113 E : CommandLine::StringVector logger_argv;
114 : CommandLine::StringVector::const_iterator it =
115 E : orig_command_line->argv().begin();
116 E : logger_argv.push_back(*(it++)); // Always copy the program.
117 E : for (; it != orig_command_line->argv().end(); ++it) {
118 E : logger_argv.push_back(*it);
119 E : if ((*it)[0] != L'-') {
120 E : ++it;
121 E : break;
122 : }
123 E : }
124 :
125 : // Strip out the (optional) sentinel which marks the split between the
126 : // two command-lines.
127 E : if (it != orig_command_line->argv().end() && *it == L"--")
128 E : ++it;
129 :
130 : // Copy the rest of the command-line arguments into a string vector for the
131 : // app command line.
132 E : CommandLine::StringVector app_argv;
133 E : for (; it != orig_command_line->argv().end(); ++it) {
134 E : app_argv.push_back(*it);
135 E : }
136 :
137 : // Initialize logger command lines with the new arguments.
138 E : logger_command_line->InitFromArgv(logger_argv);
139 :
140 : // Initialize application command lines with the new arguments.
141 E : if (!app_argv.empty()) {
142 : // Avoid switches processing in application commandLine parsing.
143 : // Otherwise, we break command like : logger.exe START -- <app> -d 1 -c 2.
144 : // We should not re-order <app> parameters.
145 E : app_command_line->reset(new CommandLine(base::FilePath(app_argv[0])));
146 E : for (size_t arg = 1; arg < app_argv.size(); ++arg)
147 E : app_command_line->get()->AppendArgNative(app_argv[arg]);
148 : }
149 :
150 E : return true;
151 E : }
152 :
153 : } // namespace common
154 : } // namespace trace
|