1 : // Copyright 2014 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/kasko/upload_thread.h"
16 :
17 : #include <windows.h>
18 : #include "base/logging.h"
19 : #include "base/files/file_path.h"
20 : #include "base/strings/string16.h"
21 : #include "base/strings/string_util.h"
22 : #include "syzygy/common/com_utils.h"
23 : #include "syzygy/kasko/waitable_timer.h"
24 :
25 : namespace kasko {
26 :
27 : // static
28 : scoped_ptr<UploadThread> UploadThread::Create(
29 : const base::FilePath& exclusive_path,
30 : scoped_ptr<WaitableTimer> waitable_timer,
31 E : const base::Closure& uploader) {
32 : // '\' is the only character not permitted in mutex names.
33 E : base::string16 escaped_path;
34 E : base::ReplaceChars(exclusive_path.value(), L"\\", L"/", &escaped_path);
35 E : base::string16 mutex_name = L"Local\\kasko_uploader_mutex_" + escaped_path;
36 : base::string16 wake_event_name =
37 E : L"Local\\kasko_uploader_wake_event_" + escaped_path;
38 E : base::win::ScopedHandle mutex(::CreateMutex(NULL, FALSE, mutex_name.c_str()));
39 E : if (!mutex) {
40 i : DWORD error = ::GetLastError();
41 i : LOG(ERROR) << "Failed to create a mutex named " << mutex_name << ": "
42 : << ::common::LogWe(error);
43 i : return scoped_ptr<UploadThread>();
44 : }
45 E : base::win::ScopedHandle stop_event(::CreateEvent(NULL, TRUE, FALSE, NULL));
46 E : if (!stop_event) {
47 i : DWORD error = ::GetLastError();
48 i : LOG(ERROR) << "Failed to create an event: " << ::common::LogWe(error);
49 i : return scoped_ptr<UploadThread>();
50 : }
51 : base::win::ScopedHandle wake_event(
52 E : ::CreateEvent(NULL, FALSE, FALSE, wake_event_name.c_str()));
53 E : if (!wake_event) {
54 i : DWORD error = ::GetLastError();
55 i : LOG(ERROR) << "Failed to create an event named '" << wake_event_name
56 : << "': " << ::common::LogWe(error);
57 i : return scoped_ptr<UploadThread>();
58 : }
59 : return make_scoped_ptr(new UploadThread(mutex.Pass(), stop_event.Pass(),
60 : wake_event.Pass(),
61 E : waitable_timer.Pass(), uploader));
62 E : }
63 :
64 E : UploadThread::~UploadThread() {
65 : // It's a bad idea to shut down without stopping the service. It's also a bad
66 : // idea to block unexpectedly in our destructor.
67 E : CHECK(!thread_impl_.HasBeenStarted() || thread_impl_.HasBeenJoined());
68 E : }
69 :
70 E : void UploadThread::Start() {
71 E : thread_impl_.Start();
72 E : }
73 :
74 E : void UploadThread::Stop() {
75 E : if (!::SetEvent(stop_event_)) {
76 i : DWORD error = ::GetLastError();
77 i : LOG(FATAL) << "Failed to signal stop event. Terminating to avoid deadlock: "
78 : << ::common::LogWe(error);
79 : }
80 E : }
81 :
82 E : void UploadThread::Join() {
83 E : Stop();
84 E : thread_impl_.Join();
85 E : }
86 :
87 E : void UploadThread::UploadOneNowAsync() {
88 E : if (!::SetEvent(wake_event_)) {
89 i : DWORD error = ::GetLastError();
90 i : LOG(ERROR) << "Failed to signal wake event: " << ::common::LogWe(error);
91 : }
92 E : }
93 :
94 : UploadThread::ThreadImpl::ThreadImpl(UploadThread* owner)
95 E : : base::SimpleThread("upload_thread"), owner_(owner) {
96 E : }
97 :
98 E : UploadThread::ThreadImpl::~ThreadImpl(){}
99 :
100 E : void UploadThread::ThreadImpl::Run() {
101 E : HANDLE handles_pre_mutex[] = {owner_->mutex_, owner_->stop_event_};
102 : DWORD wait_result = ::WaitForMultipleObjects(
103 E : arraysize(handles_pre_mutex), handles_pre_mutex, FALSE, INFINITE);
104 E : switch (wait_result) {
105 : case WAIT_OBJECT_0:
106 : case WAIT_ABANDONED_0:
107 : // mutex_
108 E : break;
109 : case WAIT_OBJECT_0 + 1:
110 : // stop_event_
111 i : return;
112 : default:
113 i : DWORD error = ::GetLastError();
114 i : LOG(ERROR) << "WaitForMultipleObjects failed: " << ::common::LogWe(error);
115 i : return;
116 : }
117 :
118 : // We have the mutex now. We will wait on the wake event, the stop event, and
119 : // the timer.
120 : HANDLE handles_post_mutex[] = {owner_->wake_event_,
121 : owner_->stop_event_,
122 E : owner_->waitable_timer_->GetHANDLE()};
123 :
124 E : while (true) {
125 E : owner_->waitable_timer_->Start();
126 : wait_result = ::WaitForMultipleObjects(arraysize(handles_post_mutex),
127 E : handles_post_mutex, FALSE, INFINITE);
128 E : switch (wait_result) {
129 : case WAIT_OBJECT_0:
130 : // wake_event_
131 E : break;
132 : case WAIT_OBJECT_0 + 1:
133 : // stop_event_
134 E : return;
135 : case WAIT_OBJECT_0 + 2:
136 : // waitable_timer_
137 E : break;
138 : default:
139 i : DWORD error = ::GetLastError();
140 i : LOG(ERROR) << "WaitForMultipleObjects failed: "
141 : << ::common::LogWe(error);
142 i : return;
143 : }
144 E : owner_->uploader_.Run();
145 E : }
146 E : }
147 :
148 : UploadThread::UploadThread(base::win::ScopedHandle mutex,
149 : base::win::ScopedHandle stop_event,
150 : base::win::ScopedHandle wake_event,
151 : scoped_ptr<WaitableTimer> waitable_timer,
152 : const base::Closure& uploader)
153 : : mutex_(mutex.Take()),
154 : stop_event_(stop_event.Take()),
155 : wake_event_(wake_event.Take()),
156 : waitable_timer_(waitable_timer.Pass()),
157 : uploader_(uploader),
158 E : thread_impl_(this) {
159 E : }
160 :
161 : } // namespace kasko
|