1 // Copyright (c) 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef PLATFORM_IMPL_PLATFORM_CLIENT_POSIX_H_
6 #define PLATFORM_IMPL_PLATFORM_CLIENT_POSIX_H_
7 
8 #include <atomic>
9 #include <memory>
10 #include <mutex>
11 #include <thread>
12 #include <vector>
13 
14 #include "absl/types/optional.h"
15 #include "platform/api/time.h"
16 #include "platform/base/macros.h"
17 #include "platform/impl/socket_handle_waiter_posix.h"
18 #include "platform/impl/task_runner.h"
19 #include "platform/impl/tls_data_router_posix.h"
20 
21 namespace openscreen {
22 
23 class UdpSocketReaderPosix;
24 
25 // Creates and provides access to singletons used by the default platform
26 // implementation. An instance must be created before an application uses any
27 // public modules in the Open Screen Library.
28 //
29 // ShutDown() should be called to destroy the PlatformClientPosix's singletons
30 // and TaskRunner to save resources when library APIs are not in use.
31 // ShutDown() calls TaskRunner::RunUntilStopped() to run any pending cleanup
32 // tasks.
33 //
34 // Create and ShutDown must be called in the same sequence.
35 //
36 // FIXME: Remove Create and Shutdown and use the ctor/dtor directly.
37 class PlatformClientPosix {
38  public:
39   // Initializes the platform implementation.
40   //
41   // |networking_loop_interval| sets the minimum amount of time that should pass
42   // between iterations of the loop used to handle networking operations. Higher
43   // values will result in less time being spent on these operations, but also
44   // less performant networking operations. Be careful setting values larger
45   // than a few hundred microseconds.
46   //
47   // |networking_operation_timeout| sets how much time may be spent on a
48   // single networking operation type.
49   //
50   // |task_runner| is a client-provided TaskRunner implementation.
51   static void Create(Clock::duration networking_operation_timeout,
52                      std::unique_ptr<TaskRunnerImpl> task_runner);
53 
54   // Initializes the platform implementation and creates a new TaskRunner (which
55   // starts a new thread).
56   static void Create(Clock::duration networking_operation_timeout);
57 
58   // Shuts down and deletes the PlatformClient instance currently stored as a
59   // singleton. This method is expected to be called before program exit. After
60   // calling this method, if the client wishes to continue using the platform
61   // library, Create() must be called again.
62   static void ShutDown();
63 
GetInstance()64   static PlatformClientPosix* GetInstance() { return instance_; }
65 
66   // This method is thread-safe.
67   // FIXME: Rename to GetTlsDataRouter()
68   TlsDataRouterPosix* tls_data_router();
69 
70   // This method is thread-safe.
71   // FIXME: Rename to GetUdpSocketReader()
72   UdpSocketReaderPosix* udp_socket_reader();
73 
74   // Returns the TaskRunner associated with this PlatformClient.
75   // NOTE: This method is expected to be thread safe.
76   TaskRunner* GetTaskRunner();
77 
78  protected:
79   // Called by ShutDown().
80   ~PlatformClientPosix();
81 
82   static void SetInstance(PlatformClientPosix* client);
83 
84  private:
85   explicit PlatformClientPosix(Clock::duration networking_operation_timeout);
86 
87   PlatformClientPosix(Clock::duration networking_operation_timeout,
88                       std::unique_ptr<TaskRunnerImpl> task_runner);
89 
90   // This method is thread-safe.
91   SocketHandleWaiterPosix* socket_handle_waiter();
92 
93   void RunNetworkLoopUntilStopped();
94 
95   std::unique_ptr<TaskRunnerImpl> task_runner_;
96 
97   // Track whether the associated instance variable has been created yet.
98   std::atomic_bool waiter_created_{false};
99   std::atomic_bool tls_data_router_created_{false};
100 
101   // Parameters for networking loop.
102   std::atomic_bool networking_loop_running_{true};
103   Clock::duration networking_loop_timeout_;
104 
105   // Flags used to ensure that initialization of below instance objects occurs
106   // only once across all threads.
107   std::once_flag waiter_initialization_;
108   std::once_flag udp_socket_reader_initialization_;
109   std::once_flag tls_data_router_initialization_;
110 
111   // Instance objects are created at runtime when they are first needed.
112   std::unique_ptr<SocketHandleWaiterPosix> waiter_;
113   std::unique_ptr<UdpSocketReaderPosix> udp_socket_reader_;
114   std::unique_ptr<TlsDataRouterPosix> tls_data_router_;
115 
116   // Threads for running TaskRunner and OperationLoop instances.
117   // NOTE: These must be declared last to avoid nondterministic failures.
118   std::thread networking_loop_thread_;
119   absl::optional<std::thread> task_runner_thread_;
120 
121   static PlatformClientPosix* instance_;
122 
123   OSP_DISALLOW_COPY_AND_ASSIGN(PlatformClientPosix);
124 };
125 
126 }  // namespace openscreen
127 
128 #endif  // PLATFORM_IMPL_PLATFORM_CLIENT_POSIX_H_
129