Update the Chromium Codelab
- New top-level //codelabs directory
- Update exercises 0-4 to compile
- Add mojo exercise
Previous codelab is here:
https://www.chromium.org/developers/cpp-in-chromium-101-codelab
Bug: N/A
Change-Id: I2218160fa9efc8017dce809db8546604ade7e5d8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2414488
Reviewed-by: Victor Costan <[email protected]>
Reviewed-by: Dirk Pranke <[email protected]>
Reviewed-by: Scott Violet <[email protected]>
Reviewed-by: Marijn Kruisselbrink <[email protected]>
Reviewed-by: danakj <[email protected]>
Reviewed-by: enne <[email protected]>
Commit-Queue: Austin Sullivan <[email protected]>
Cr-Commit-Position: refs/heads/master@{#814678}
diff --git a/BUILD.gn b/BUILD.gn
index 58c9429..8600b7d 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -73,6 +73,7 @@
"//base/util:base_util_unittests",
"//chrome/installer",
"//chrome/updater",
+ "//codelabs",
"//components:components_unittests",
"//components/gwp_asan:gwp_asan_unittests",
"//net:net_unittests",
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 69af581..2e6e7ca 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -68,6 +68,8 @@
r'ios[\\/].*_app_interface\.mm$',
# Views Examples code
r'ui[\\/]views[\\/]examples[\\/].*',
+ # Chromium Codelab
+ r'codelabs[\\/]*'
)
_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
diff --git a/codelabs/BUILD.gn b/codelabs/BUILD.gn
new file mode 100644
index 0000000..167bc5b5
--- /dev/null
+++ b/codelabs/BUILD.gn
@@ -0,0 +1,54 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+group("codelabs") {
+ testonly = true
+ deps = [
+ ":codelab_factor",
+ ":codelab_fibonacci",
+ ":codelab_hello_world",
+ ":codelab_mojo",
+ ":codelab_sleep",
+ ]
+}
+
+executable("codelab_hello_world") {
+ sources = [ "cpp101/hello_world.cc" ]
+ deps = [ "//base" ]
+}
+
+executable("codelab_fibonacci") {
+ sources = [ "cpp101/fibonacci.cc" ]
+ deps = [ "//base" ]
+}
+
+executable("codelab_sleep") {
+ testonly = true
+ sources = [ "cpp101/sleep.cc" ]
+ deps = [
+ "//base",
+ "//base/test:test_support",
+ ]
+}
+
+executable("codelab_factor") {
+ testonly = true
+ sources = [ "cpp101/factor.cc" ]
+ deps = [
+ "//base",
+ "//base/test:test_support",
+ ]
+}
+
+executable("codelab_mojo") {
+ testonly = true
+ sources = [ "cpp101/mojo.cc" ]
+ deps = [
+ "//base",
+ "//base/test:test_support",
+ "//codelabs/cpp101/services/math/",
+ "//mojo/core/embedder",
+ "//mojo/public/cpp/base",
+ ]
+}
diff --git a/codelabs/DEPS b/codelabs/DEPS
new file mode 100644
index 0000000..6ea1c24
--- /dev/null
+++ b/codelabs/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+mojo/core/embedder",
+ "+mojo/public/cpp/bindings",
+]
diff --git a/codelabs/OWNERS b/codelabs/OWNERS
new file mode 100644
index 0000000..f59ec20
--- /dev/null
+++ b/codelabs/OWNERS
@@ -0,0 +1 @@
+*
\ No newline at end of file
diff --git a/codelabs/README.md b/codelabs/README.md
new file mode 100644
index 0000000..def37a73
--- /dev/null
+++ b/codelabs/README.md
@@ -0,0 +1,13 @@
+# Chromium Codelab
+
+See the `cpp101/` directory for the Chromium C++ codelab,
+including example solutions.
+
+## Motivation
+
+The goal of this codelab is to introduce new Chromium developers to both the
+important design patterns and the style of code they can expect to become
+familiar with.
+
+The code in this directory is for documentation purposes only. It is compiled
+via the top level BUILD.gn's `gn_all` target to make sure it is kept up to date.
diff --git a/codelabs/cpp101/codelab.md b/codelabs/cpp101/codelab.md
new file mode 100644
index 0000000..ddac55c
--- /dev/null
+++ b/codelabs/cpp101/codelab.md
@@ -0,0 +1,282 @@
+# C++ in Chromium 101 - Codelab
+
+This tutorial will guide you through the creation of various example C++
+applications, highlighting important Chromium C++ concepts.
+This tutorial assumes robust knowledge of C++ (the language) but does not
+assume you know how to write an application specific to Chromium's style and
+architecture. This tutorial does assume that you know how to check files out
+of Chromium's repository.
+
+As always, consider the following resources as of primary importance:
+
+- [Coding Style](https://chromium.googlesource.com/chromium/src/+/master/styleguide/styleguide.md)
+- [Callback<> and Bind()](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/callback.md)
+- [Threading and Tasks in Chrome](https://chromium.googlesource.com/chromium/src/+/master/docs/threading_and_tasks.md)
+- [Intro to Mojo & Services](https://chromium.googlesource.com/chromium/src.git/+/master/docs/mojo_and_services.md)
+- [Important Abstractions and Data Structures](https://sites.google.com/a/chromium.org/dev/developers/coding-style/important-abstractions-and-data-structures) (badly needs updating)
+
+This tutorial does not assume you have read any of the above,
+though you should feel free to peruse them when necessary.
+This tutorial will cover information across all of those guides.
+
+Exercise solutions are available in the `codelabs/cpp101/` directory of the
+Chromium source code. Build all of the example solutions with
+`autoninja -C out/Default codelabs`. You are encouraged to create a new
+`base/cpp101/` directory locally if you want to try implementing these
+exercises yourself.
+
+### Exercise 0: "Hello World!"
+
+This exercise demonstrates the use of the [ninja](https://ninja-build.org/)
+build system to build a simple C++ binary and demonstrates how typical C++
+builds are organized within Chromium.
+
+Create a new target in `base/BUILD.gn` for a new executable
+named `codelab_hello_world`. Then write the classic "Hello, world!" program in
+C++. You should be able to build it with
+`autoninja -C out/Default codelab_hello_world` and execute it directly by
+finding the binary within `out/Default`.
+
+Sample execution:
+```shell
+$ cd /path/to/chromium/src
+$ gclient runhooks
+$ autoninja -C out/Default codelab_hello_world
+$ out/Default/codelab_hello_world
+Hello, world!
+[0923/185218.645640:INFO:hello_world.cc(27)] Hello, world!
+```
+
+### More information
+
+[Git Tips](https://chromium.googlesource.com/chromium/src.git/+/master/docs/git_tips.md)
+and [Git Cookbook](https://chromium.googlesource.com/chromium/src.git/+/master/docs/git_cookbook.md)
+
+[Life of a Chromium Developer](https://docs.google.com/a/google.com/presentation/d/1abnqM9j6zFodPHA38JG1061rG2iGj_GABxEDgZsdbJg/)
+
+## Part 1: Using command-line arguments
+
+We will augment our `codelab_hello_world` binary to parse command-line flags and
+use those values to print messages to the user.
+
+Command-line arguments within Chromium are processed by the
+`CommandLine::Init()` function, which takes command line flags from the
+[argc and argv](https://crasseux.com/books/ctutorial/argc-and-argv.html)
+(argument count & vector) variables of the main() method. A typical invocation
+of `CommandLine::Init()` looks like the following:
+```cpp
+int main(int argc, char** argv) {
+ CommandLine::Init(argc, argv);
+ // Main program execution ...
+ return 0;
+}
+```
+Flags are not explicitly defined in Chromium. Instead, we
+use `GetSwitchValueASCII()` and friends to retrieve values passed in.
+
+### Important include files
+
+```cpp
+#include "base/command_line.h"
+#include "base/logging.h"
+```
+
+### Exercise 1: Using command-line arguments
+
+Change `codelab_hello_world` to take a `--greeting` and a `--name` switch.
+The greeting, if not specified, should default to "Hello",
+and the name, if not specified, should default to "World".
+
+## Part 2: Callbacks and Bind
+
+C++, unlike other languages such as Python, Javascript, or Lisp, has only
+rudimentary support for [callbacks](https://en.wikipedia.org/wiki/Callbacks)
+and no support for
+[partial application](https://en.wikipedia.org/wiki/Partial_application).
+However, Chromium has the `base::OnceCallback<Sig>` and
+ `base::RepeatingCallback<Sig>`class, whose instances can be freely passed
+around, returned, and generally be treated as first-class values.
+base::OnceCallback<Sig> is the move-only, single-call variant,
+and base::RepeatingCallback<Sig> is the copyable, multiple-call variant.
+
+The `Sig` template parameter is a function signature type:
+```cpp
+// The type of a callback that:
+// - Can run only once.
+// - Is move-only and non-copyable.
+// - Takes no arguments and does not return anything.
+// base::OnceClosure is an alias of this type.
+base::OnceCallback<void()>
+
+// The type of a callback that:
+// - Can run more than once.
+// - Is copyable.
+// - Takes no arguments and does not return anything.
+// base::RepeatingClosure is an alias of this type.
+base::RepeatingCallback<void()>
+
+// The types of a callback that takes two arguments (a string and a double)
+// and returns an int.
+base::OnceCallback<int(std::string, double)>
+base::RepeatingCallback<int(std::string, double)>
+```
+Callbacks are executed by invoking the `Run()` member function.
+base::OnceCallback<Sig> needs to be rvalue to run.
+```cpp
+void MyFunction1(base::OnceCallback<int(std::string, double)> my_callback) {
+ // OnceCallback
+ int result1 = std::move(my_callback).Run("my string 1", 1.0);
+
+ // After running a OnceCallback, it's consumed and nulled out.
+ DCHECK(!my_callback);
+ ...
+}
+
+void MyFunction2(base::RepeatingCallback<int(std::string, double)> my_callback) {
+ int result1 = my_callback.Run("my string 1", 1.0);
+ // Run() can be called as many times as you wish for RepeatingCallback.
+ int result2 = my_callback.Run("my string 2", 2);
+ ...
+```
+Callbacks are constructed using the `base::BindOnce()` or `base::BindRepeating()` function,
+which handles partial application:
+```cpp
+// Declare a function.
+void MyFunction(int32 a, double b);
+
+base::OnceCallback<void(double)> my_callback1 = base::BindOnce(&MyFunction, 10);
+base::RepeatingCallback<void(double)> my_callback2 = base::BindRepeating(&MyFunction, 10);
+
+// Equivalent to:
+//
+// MyFunction(10, 3.5);
+//
+std::move(my_callback1).Run(3.5);
+my_callback2.Run(3.5);
+```
+`base::BindOnce()` and `base::BindRepeating()` can do a lot more, including
+binding class member functions and binding additional arguments to an
+existing `base::OnceCallback` or `base::RepeatingCallback`. See
+[docs/callback.md](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/callback.md)
+for details.
+
+### Important Include Files
+
+```cpp
+#include "base/bind.h"
+#include "base/callback.h"
+```
+
+### More Information
+
+[Callback<> and Bind()](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/callback.md)
+
+### Exercise 2: Fibonacci closures
+
+Implement a function that returns a callback that takes no arguments and returns
+successive Fibonacci numbers. That is, a function that can be used like this:
+```cpp
+base::RepeatingCallback<int()> fibonacci_closure = MakeFibonacciClosure();
+LOG(INFO) << fibonacci_closure.Run(); // Prints "1"
+LOG(INFO) << fibonacci_closure.Run(); // Prints "1"
+LOG(INFO) << fibonacci_closure.Run(); // Prints "2"
+...
+```
+Each returned Fibonacci callback should be independent;
+running one callback shouldn't affect the result of running another callback.
+Write a `fibonacci` executable that takes an integer argument `n`
+and uses your function to print out the first `n` Fibonacci numbers.
+
+(This exercise was inspired by
+[this Go exercise: Function closures](https://tour.golang.org/moretypes/25).)
+
+## Part 3: Threads and task runners
+
+Chromium has a number of abstractions for sequencing and threading.
+[Threading and Tasks in Chrome](https://chromium.googlesource.com/chromium/src/+/master/docs/threading_and_tasks.md)
+is a must-read and go-to reference for anything related to tasks, thread pools,
+task runners, and more.
+
+Sequenced execution (on virtual threads) is strongly preferred to
+single-threaded execution (on physical threads). Chromium's abstraction for
+asynchronously running posted tasks is `base::TaskRunner`. Task runners allow
+you to write code that posts tasks without depending on what exactly will run
+those tasks.
+
+`base::SequencedTaskRunner` (which extends `base::TaskRunner`) is a commonly
+used abstraction which handles running tasks (which are instances
+of `base::Closure`) in sequential order. These tasks are not guaranteed to run
+on the same thread. The preferred way of posting to the current (virtual) thread
+is `base::SequencedTaskRunnerHandle::Get()`.
+
+A task that can run on any thread and doesn’t have ordering or mutual exclusion
+requirements with other tasks should be posted using one of the
+`base::ThreadPool::PostTask()` functions.
+
+There are a number of ways to post tasks to a thread pool or task runner.
+
+- `PostTask()`
+- `PostDelayedTask()` if you want to add a delay.
+- `PostTaskAndReply()` lets you post a task which will post a task back to your
+ current thread when its done.
+- `PostTaskAndReplyWithResult()` to automatically pass the return value of the
+ first call as argument to the second call.
+
+Normally you wouldn't have to worry about setting up a threading environment and
+keeping it running, since that is automatically done by Chromium's thread
+classes. However, since the main thread doesn't automatically start off with
+`TaskEnvironment`, there's a bit of extra setup involved. This setup code is
+available in the exercise solution files.
+
+### Important header files
+```cpp
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/time/time.h"
+```
+
+### Exercise 3a: Sleep
+
+Implement the Unix command-line utility `sleep` using only
+a `base::SequencedTaskRunnerHandle` (i.e., without using the `sleep` function
+or `base::PlatformThread::Sleep`).
+
+### Exercise 3b: Integer factorization
+
+Take the given (slow) function to find a non-trivial factor of a given integer:
+```cpp
+bool FindNonTrivialFactor(int n, int* factor) {
+ // Really naive algorithm.
+ for (int i = n-1; i >= 2; --i) {
+ if (n % i == 0) {
+ *factor = i;
+ return true;
+ }
+ }
+ return false;
+}
+```
+Write a command-line utility `factor` that takes a number, posts a task to the
+background using `FindNonTrivialFactor`, and prints a status update every second
+as long as the factoring task is executing.
+
+### More information
+
+[Threading and Tasks in Chrome](https://chromium.googlesource.com/chromium/src/+/master/docs/threading_and_tasks.md)
+
+## Part 4: Mojo
+
+Mojo is Chromium's abstraction of IPC. Mojo allows for developers to easily
+connect interface clients and implementations across arbitrary intra- and
+inter-process boundaries. See the
+[Intro to Mojo and Services](https://chromium.googlesource.com/chromium/src.git/+/master/docs/mojo_and_services.md)
+guide to get started.
+
+ ### Exercise 4: Building a simple out-of-process service
+
+See the [building a simple out-of-process service](https://chromium.googlesource.com/chromium/src.git/+/master/docs/mojo_and_services.md#example_building-a-simple-out_of_process-service)
+tutorial on using Mojo to define, hook up, and launch an out-of-process service.
+
+### More Information
+
+[Mojo C++ Bindings API Docs](https://chromium.googlesource.com/chromium/src.git/+/master/mojo/public/cpp/bindings/README.md)
+[Mojo Docs](https://chromium.googlesource.com/chromium/src.git/+/master/mojo/README.md)
diff --git a/codelabs/cpp101/factor.cc b/codelabs/cpp101/factor.cc
new file mode 100644
index 0000000..119a2e7
--- /dev/null
+++ b/codelabs/cpp101/factor.cc
@@ -0,0 +1,94 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/at_exit.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/optional.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/task/thread_pool.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/time/time.h"
+
+namespace {
+
+base::Optional<int> FindNonTrivialFactor(int n) {
+ // Really naive algorithm.
+ for (int i = 2; i < n; ++i) {
+ if (n % i == 0) {
+ return i;
+ }
+ }
+ return base::nullopt;
+}
+
+void FindNonTrivialFactorHelper(int n, base::Optional<int>* result) {
+ *result = FindNonTrivialFactor(n);
+}
+
+void PrintStatusUpdate(base::TimeTicks start_time) {
+ double num_seconds = (base::TimeTicks::Now() - start_time).InSecondsF();
+ LOG(INFO) << "Waited for " << num_seconds << " seconds...\n";
+}
+
+void PrintStatusUpdateRepeatedly(base::TimeTicks start_time,
+ base::TimeDelta print_interval) {
+ PrintStatusUpdate(start_time);
+ base::ThreadPool::PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&PrintStatusUpdateRepeatedly, start_time, print_interval),
+ print_interval);
+}
+
+} // namespace
+
+int main(int argc, char* argv[]) {
+ base::AtExitManager exit_manager;
+ base::CommandLine::Init(argc, argv);
+ TestTimeouts::Initialize();
+ base::test::TaskEnvironment task_environment{
+ base::test::TaskEnvironment::TimeSource::SYSTEM_TIME};
+
+ if (argc <= 1) {
+ LOG(INFO) << argv[0] << ": missing operand\n";
+ return -1;
+ }
+
+ int n = 0;
+ if (!base::StringToInt(argv[1], &n) || n < 2) {
+ LOG(INFO) << argv[0] << ": invalid n '" << argv[1] << "'";
+ return -1;
+ }
+
+ base::RunLoop run_loop;
+
+ base::Optional<int> result;
+ // Notice that we're posting the long-running factoring operation to
+ // |base::ThreadPool| to avoid blocking the main thread
+ //
+ // |run_loop.QuitClosure()| will be called once the factoring task completes.
+ base::ThreadPool::PostTaskAndReply(
+ FROM_HERE, base::BindOnce(&FindNonTrivialFactorHelper, n, &result),
+ run_loop.QuitClosure());
+
+ base::ThreadPool::PostTask(
+ FROM_HERE,
+ base::BindOnce(&PrintStatusUpdateRepeatedly, base::TimeTicks::Now(),
+ base::TimeDelta::FromSeconds(1)));
+
+ run_loop.Run();
+
+ if (result.has_value()) {
+ LOG(INFO) << "found non-trivial factor " << result.value() << " for " << n;
+ DCHECK_EQ(n % result.value(), 0);
+ } else {
+ LOG(INFO) << n << " is prime";
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/codelabs/cpp101/fibonacci.cc b/codelabs/cpp101/fibonacci.cc
new file mode 100644
index 0000000..fcabcd64
--- /dev/null
+++ b/codelabs/cpp101/fibonacci.cc
@@ -0,0 +1,60 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+
+namespace {
+
+struct FibonacciState {
+ FibonacciState() = default;
+
+ int i{0}, j{1};
+};
+
+int ComputeNextFibonacciNumber(FibonacciState* state) {
+ int next = state->i + state->j;
+ state->i = state->j;
+ state->j = next;
+ return state->i;
+}
+
+base::RepeatingCallback<int()> MakeFibonacciClosure() {
+ auto state = std::make_unique<FibonacciState>();
+ return base::BindRepeating(&ComputeNextFibonacciNumber,
+ base::Owned(std::move(state)));
+}
+
+} // namespace
+
+int main(int argc, char* argv[]) {
+ if (argc <= 1) {
+ LOG(INFO) << argv[0] << ": missing operand";
+ return -1;
+ }
+
+ int n = 0;
+ if (!base::StringToInt(argv[1], &n) || n < 0) {
+ LOG(INFO) << argv[0] << ": invalid n '" << argv[1] << "'";
+ return -1;
+ }
+
+ // |fibonacci_closure1| and |fibonacci_closure2| are independent. Though they
+ // are bound to the same method, they each have their own |FibonacciState|.
+ // Running one closure does not affect the other.
+ base::RepeatingCallback<int()> fibonacci_closure1 = MakeFibonacciClosure();
+ base::RepeatingCallback<int()> fibonacci_closure2 = MakeFibonacciClosure();
+ for (int i = 0; i < n; ++i) {
+ // Run both closures and confirm the values match.
+ int fibonacci_i = fibonacci_closure1.Run();
+ int fibonacci_i_backup = fibonacci_closure2.Run();
+ DCHECK_EQ(fibonacci_i, fibonacci_i_backup);
+
+ LOG(INFO) << "F_" << i << " = " << fibonacci_i;
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/codelabs/cpp101/hello_world.cc b/codelabs/cpp101/hello_world.cc
new file mode 100644
index 0000000..6642faeb
--- /dev/null
+++ b/codelabs/cpp101/hello_world.cc
@@ -0,0 +1,28 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+
+#include <string>
+
+#include "base/command_line.h"
+#include "base/logging.h"
+
+int main(int argc, char* argv[]) {
+ CHECK(base::CommandLine::Init(argc, argv));
+
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+
+ std::string greeting = command_line.GetSwitchValueASCII("greeting");
+ if (greeting.empty())
+ greeting = "Hello";
+
+ std::string name = command_line.GetSwitchValueASCII("name");
+ if (name.empty())
+ name = "world";
+
+ CHECK_GT(printf("%s, %s!\n", greeting.c_str(), name.c_str()), 0);
+ LOG(INFO) << greeting << ", " << name << "!";
+}
\ No newline at end of file
diff --git a/codelabs/cpp101/mojo.cc b/codelabs/cpp101/mojo.cc
new file mode 100644
index 0000000..e51e5f2
--- /dev/null
+++ b/codelabs/cpp101/mojo.cc
@@ -0,0 +1,62 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/at_exit.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_timeouts.h"
+#include "codelabs/cpp101/services/math/math_service.h"
+#include "mojo/core/embedder/embedder.h"
+#include "mojo/public/cpp/bindings/remote.h"
+
+int main(int argc, char* argv[]) {
+ base::AtExitManager exit_manager;
+ base::CommandLine::Init(argc, argv);
+ TestTimeouts::Initialize();
+ base::test::TaskEnvironment task_environment{
+ base::test::TaskEnvironment::TimeSource::SYSTEM_TIME};
+ mojo::core::Init();
+
+ if (argc <= 2) {
+ LOG(INFO) << argv[0] << ": missing operand";
+ return -1;
+ }
+
+ int divisor = 0;
+ if (!base::StringToInt(argv[1], &divisor)) {
+ LOG(INFO) << argv[0] << ": invalid divisor '" << argv[1] << "'";
+ return -1;
+ }
+
+ int dividend = 0;
+ if (!base::StringToInt(argv[2], ÷nd) || dividend == 0) {
+ LOG(INFO) << argv[0] << ": invalid divisor '" << argv[2] << "'";
+ return -1;
+ }
+
+ base::RunLoop run_loop;
+
+ mojo::Remote<math::mojom::MathService> math_service;
+ math::MathService math_service_impl(
+ math_service.BindNewPipeAndPassReceiver());
+
+ math_service->Divide(divisor, dividend,
+ base::BindOnce(
+ [](base::OnceClosure quit, int32_t quotient) {
+ LOG(INFO) << "Quotient: " << quotient;
+ std::move(quit).Run();
+ },
+ run_loop.QuitClosure()));
+
+ run_loop.Run();
+
+ return 0;
+}
\ No newline at end of file
diff --git a/codelabs/cpp101/services/math/BUILD.gn b/codelabs/cpp101/services/math/BUILD.gn
new file mode 100644
index 0000000..64a14b5
--- /dev/null
+++ b/codelabs/cpp101/services/math/BUILD.gn
@@ -0,0 +1,15 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("math") {
+ sources = [
+ "math_service.cc",
+ "math_service.h",
+ ]
+
+ deps = [
+ "public/mojom",
+ "//base",
+ ]
+}
diff --git a/codelabs/cpp101/services/math/math_service.cc b/codelabs/cpp101/services/math/math_service.cc
new file mode 100644
index 0000000..1054382e
--- /dev/null
+++ b/codelabs/cpp101/services/math/math_service.cc
@@ -0,0 +1,21 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "math_service.h"
+
+namespace math {
+
+MathService::MathService(mojo::PendingReceiver<mojom::MathService> receiver)
+ : receiver_(this, std::move(receiver)) {}
+
+MathService::~MathService() = default;
+
+void MathService::Divide(int32_t dividend,
+ int32_t divisor,
+ DivideCallback callback) {
+ // Respond with the quotient!
+ std::move(callback).Run(dividend / divisor);
+}
+
+} // namespace math
diff --git a/codelabs/cpp101/services/math/math_service.h b/codelabs/cpp101/services/math/math_service.h
new file mode 100644
index 0000000..59442f9
--- /dev/null
+++ b/codelabs/cpp101/services/math/math_service.h
@@ -0,0 +1,32 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CODELABS_CPP101_SERVICES_MATH_MATH_SERVICE_H_
+#define CODELABS_CPP101_SERVICES_MATH_MATH_SERVICE_H_
+
+#include "base/macros.h"
+#include "codelabs/cpp101/services/math/public/mojom/math_service.mojom.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+
+namespace math {
+
+class MathService : public mojom::MathService {
+ public:
+ explicit MathService(mojo::PendingReceiver<mojom::MathService> receiver);
+ ~MathService() override;
+ MathService(const MathService&) = delete;
+ MathService& operator=(const MathService&) = delete;
+
+ private:
+ // mojom::MathService:
+ void Divide(int32_t dividend,
+ int32_t divisor,
+ DivideCallback callback) override;
+
+ mojo::Receiver<mojom::MathService> receiver_;
+};
+
+} // namespace math
+
+#endif // CODELABS_CPP101_SERVICES_MATH_MATH_SERVICE_H_
\ No newline at end of file
diff --git a/codelabs/cpp101/services/math/public/mojom/BUILD.gn b/codelabs/cpp101/services/math/public/mojom/BUILD.gn
new file mode 100644
index 0000000..c386981
--- /dev/null
+++ b/codelabs/cpp101/services/math/public/mojom/BUILD.gn
@@ -0,0 +1,9 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("mojom") {
+ sources = [ "math_service.mojom" ]
+}
diff --git a/codelabs/cpp101/services/math/public/mojom/OWNERS b/codelabs/cpp101/services/math/public/mojom/OWNERS
new file mode 100644
index 0000000..61b5e28
--- /dev/null
+++ b/codelabs/cpp101/services/math/public/mojom/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
\ No newline at end of file
diff --git a/codelabs/cpp101/services/math/public/mojom/math_service.mojom b/codelabs/cpp101/services/math/public/mojom/math_service.mojom
new file mode 100644
index 0000000..2c958fc
--- /dev/null
+++ b/codelabs/cpp101/services/math/public/mojom/math_service.mojom
@@ -0,0 +1,9 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module math.mojom;
+
+interface MathService {
+ Divide(int32 dividend, int32 divisor) => (int32 quotient);
+};
diff --git a/codelabs/cpp101/sleep.cc b/codelabs/cpp101/sleep.cc
new file mode 100644
index 0000000..e0aec69
--- /dev/null
+++ b/codelabs/cpp101/sleep.cc
@@ -0,0 +1,50 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/at_exit.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/time/time.h"
+
+int main(int argc, char* argv[]) {
+ base::AtExitManager exit_manager;
+ base::CommandLine::Init(argc, argv);
+ TestTimeouts::Initialize();
+ base::test::TaskEnvironment task_environment{
+ base::test::TaskEnvironment::TimeSource::SYSTEM_TIME};
+
+ if (argc <= 1) {
+ LOG(INFO) << argv[0] << ": missing operand";
+ return -1;
+ }
+
+ int duration_seconds = 0;
+ if (!base::StringToInt(argv[1], &duration_seconds) || duration_seconds < 0) {
+ LOG(INFO) << ": invalid time interval '" << argv[1] << "'";
+ return -1;
+ }
+
+ base::RunLoop run_loop;
+ base::TimeDelta duration = base::TimeDelta::FromSeconds(duration_seconds);
+
+ base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::BindOnce(run_loop.QuitClosure()), duration);
+
+ // Tasks are run asynchronously, so this will print before the task runs.
+ LOG(INFO) << "Going to sleep for " << duration_seconds << " seconds...";
+
+ // Runs all the tasks that have been posted to the |SequencedTaskRunner|.
+ run_loop.Run();
+
+ // This will NOT complete until |run_loop.QuitClosure()| runs.
+ LOG(INFO) << "I'm awake!";
+
+ return 0;
+}
\ No newline at end of file