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