blob: ae1f199b68ab2f71237c874239dc6690af3031f5 [file] [log] [blame] [view]
Artem Titova6178672023-01-30 10:51:011<!-- go/cmark -->
2<!--* freshness: {owner: 'hta' reviewed: '2021-05-31'} *-->
Harald Alvestrand5cb983b2021-06-01 07:46:543
4# Basic concepts and primitives
5
6## Time
7
8Internally, time is represent using the [webrtc::Timestamp][1] class. This
9represents
10time with a resolution of one microsecond, using a 64-bit integer, and provides
11converters to milliseconds or seconds as needed.
12
13All timestamps need to be measured from the system monotonic time.
14
15The epoch is not specified (because we can't always know if the system clock is
16correct), but whenever an absolute epoch is needed, the Unix time
17epoch (Jan 1, 1970 at 0:00 GMT) is used.
18
19Conversion from/to other formats (for example milliseconds, NTP times,
20timestamp strings) should happen as close to the interface requiring that
21format as possible.
22
23NOTE: There are parts of the codebase that don't use Timestamp, parts of the
24codebase that use the NTP epoch, and parts of the codebase that don't use the
25monotonic clock. They need to
26be updated.
27
28## Threads
29
30All execution happens on a TaskQueue instance. How a TaskQueue is implemented
31varies by platform, but they all have the [webrtc::TaskQueueBase][3] API.
32
33This API offers primitives for posting tasks, with or without delay.
34
35Some core parts use the [rtc::Thread][2], which is a subclass of TaskQueueBase.
36This may contain a SocketServer for processing I/O, and is used for policing
37certain calling pattern between a few core threads (the NetworkThread cannot
38do Invoke on the Worker thread, for instance).
39
Harald Alvestrandc1be89f2022-06-21 09:28:3240## Reserved class suffixes
41
42C++ classes with names ending in the suffixes "Factory", "Builder" and "Manager" are supposed to behave
43in certain well known ways.
44
45For a particular class name Foo, the following classes, if they exist, should
46behave as follows:
47
48* FooFactory: Has a Create function that creates a Foo object and returns the
49 object or an owning reference to it (for instance std::unique_ptr or
50 rtc::scoped_refptr<Foo>). The Create function should NOT alter the factory
51 state; ideally, it is marked const. Ownership of the returned object is only
52 with the caller.
53
54* FooBuilder: Has a Build function that returns ownership of a Foo object (as
55 above). The Builder can only be used once, and resources given to the Builder
56 before the Build function is called are either released or owned by the Foo
57 object. The Create function may be reference-qualified (declared as ```Foo
58 Build() &&```), which means it is invoked as ```std::move(builder).Build()```,
59 and C++ will ensure that it is not used again.
60
61* FooManager: Has a Create function that returns an rtc::scoped_refptr<Foo> (if
62 shared ownership) or a Foo* (if the Manager retains sole ownership). If
63 Create() cannot fail, consider returning a Foo&. The Manager is responsible
64 for keeping track of the object; if the Create function returns a Foo*, the
65 Foo object is guaranteed to be destroyed when the FooManager is destroyed.
66
67If a Manager class manages multiple classes of objects, the Create functions
68should be appropriately named (the FooAndBarManager would have CreateFoo() and
69CreateBar() functions), and the class will have a suitable name for the group of
70objects it is managing.
71
72FooFactory is mainly useful for the case where preparation for producing Foo
73objects is complex. If Foo can be created with just an argument list, consider
74exposing its constructor instead; if Foo creation can fail, consider having
75a free function called CreateFoo instead of a factory.
76
77Note that classes with these names exist that do not follow these conventions.
78When they are detected, they need to be marked with TODO statements and bugs
79filed on them to get them into a conformant state.
80
Harald Alvestrand5cb983b2021-06-01 07:46:5481## Synchronization primitives
82
83### PostTask and thread-guarded variables
84
85The preferred method for synchronization is to post tasks between threads,
86and to let each thread take care of its own variables (lock-free programming).
87All variables in
88classes intended to be used with multiple threads should therefore be
89annotated with RTC_GUARDED_BY(thread).
90
91For classes used with only one thread, the recommended pattern is to let
92them own a webrtc::SequenceChecker (conventionally named sequence_checker_)
93and let all variables be RTC_GUARDED_BY(sequence_checker_).
94
95Member variables marked const do not need to be guarded, since they never
96change. (But note that they may point to objects that can change!)
97
98When posting tasks with callbacks, it is the duty of the caller to check
99that the object one is calling back into still exists when the callback
100is made. A helper for this task is the [webrtc::ScopedTaskSafety][5]
101flag, which can automatically drop callbacks in this situation, and
102associated classes.
103
104### Synchronization primitives to be used when needed
105
106When it is absolutely necessary to let one thread wait for another thread
107to do something, Thread::Invoke can be used. This function is DISCOURAGED,
108since it leads to performance issues, but is currently still widespread.
109
110When it is absolutely necessary to access one variable from multiple threads,
111the webrtc::Mutex can be used. Such variables MUST be marked up with
112RTC_GUARDED_BY(mutex), to allow static analysis that lessens the chance of
113deadlocks or unintended consequences.
114
115### Synchronization primitives that are being removed
116The following non-exhaustive list of synchronization primitives are
117in the (slow) process of being removed from the codebase.
118
119* sigslot. Use [webrtc::CallbackList][4] instead, or, when there's only one
120 signal consumer, a single std::function.
121
122* AsyncInvoker.
123
Harald Alvestrand0fe60bd2021-06-22 07:47:34124* RecursiveCriticalSection. Try to use [webrtc::Mutex][6] instead, and don't recurse.
125
Harald Alvestrand31b03e92021-11-02 10:54:38126## Enum-To-String functions
127If there is a need to convert an enum to a string representation, such as for
128enums exposed at the Javascript API interface, the recommended way is to write
129a function named AsString, declared "static constexpr" and returning an
130absl::string_view. The declaration should be right after the enum declaration,
131in the same scope; the implementation (which must be marked "inline") should
132be at the end of the same header file.
Harald Alvestrand5cb983b2021-06-01 07:46:54133
Harald Alvestrand31b03e92021-11-02 10:54:38134If the enum is not defined within a class, the "static" keyword is not needed.
Harald Alvestrand5cb983b2021-06-01 07:46:54135
136[1]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/api/units/timestamp.h;drc=b95d90b78a3491ef8e8aa0640dd521515ec881ca;l=29
137[2]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/rtc_base/thread.h;drc=1107751b6f11c35259a1c5c8a0f716e227b7e3b4;l=194
138[3]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/api/task_queue/task_queue_base.h;drc=1107751b6f11c35259a1c5c8a0f716e227b7e3b4;l=25
139[4]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/rtc_base/callback_list.h;drc=54b91412de3f579a2d5ccdead6e04cc2cc5ca3a1;l=162
140[5]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/rtc_base/task_utils/pending_task_safety_flag.h;drc=86ee89f73e4f4799b3ebcc0b5c65837c9601fe6d;l=117
Harald Alvestrand0fe60bd2021-06-22 07:47:34141[6]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/rtc_base/synchronization/mutex.h;drc=0d3c09a8fe5f12dfbc9f1bcd5790fda8830624ec;l=40