1e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#ifndef ANDROID_PDX_SERVICE_DISPATCHER_H_
2e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#define ANDROID_PDX_SERVICE_DISPATCHER_H_
3e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
4e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <memory>
55a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko#include <mutex>
65a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko#include <unordered_map>
75a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko#include <vector>
85a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko
95a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko#include <pdx/file_handle.h>
10e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
11e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkonamespace android {
12e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkonamespace pdx {
13e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
14e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkoclass Service;
15e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
16e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko/*
17e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko * ServiceDispatcher manages a list of Service instances and handles message
18e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko * reception and dispatch to the services. This makes repetitive dispatch tasks
19e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko * easier to implement.
20e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko */
21e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkoclass ServiceDispatcher {
22e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko public:
235a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko  // Get a new instance of ServiceDispatcher, or return nullptr if init failed.
245a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko  static std::unique_ptr<ServiceDispatcher> Create();
255a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko
265a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko  ~ServiceDispatcher();
27e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
28e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  /*
29e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * Adds a service to the list of services handled by this dispatcher. This
30e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * will fail if any threads are blocked waiting for messages in this
31e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * dispatcher.
32e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   *
33e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * Returns 0 on success; -EEXIST if the service was already added.
34e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   */
355a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko  int AddService(const std::shared_ptr<Service>& service);
36e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
37e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  /*
38e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * Removes a service from this dispatcher. This will fail if any threads are
39e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * blocked waiting for messages in this dispatcher.
40e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   *
41e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * Returns 0 on success; -ENOENT if the service was not previously added;
42e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * -EBUSY if there are threads in the dispatcher.
43e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   */
445a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko  int RemoveService(const std::shared_ptr<Service>& service);
45e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
46e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  /*
47e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * Receive and dispatch one set of messages. Multiple threads may enter this
48e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * method to create an implicit thread pool, as described for
49e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * enterDispatchLoop() below, however this method exits after one dispatch
50e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * cycle, requiring an external loop. This is useful when other work needs
51e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * to be done in the service dispatch loop.
52e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   */
535a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko  int ReceiveAndDispatch();
54e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
55e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  /*
56e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * Same as above with timeout in milliseconds. A negative value means
57e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * infinite timeout, while a value of 0 means return immediately if no
58e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * messages are available to receive.
59e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   */
605a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko  int ReceiveAndDispatch(int timeout);
61e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
62e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  /*
63e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * Receive and dispatch messages until canceled. When more than one thread
64e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * enters this method it creates an implicit thread pool to dispatch messages.
65e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * Explicit thread pools may be created by using a single dispatch thread that
66e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * hands Message instances (via move assignment) over to a queue of threads
67e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * (or perhaps one of several) to handle.
68e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   */
695a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko  int EnterDispatchLoop();
70e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
71e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  /*
72e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * Sets the canceled state of the dispatcher. When canceled is true, any
73e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * threads blocked waiting for messages will return. This method waits until
74e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * all dispatch threads have exited the dispatcher.
75e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   */
765a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko  void SetCanceled(bool cancel);
77e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
78e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  /*
79e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   * Gets the canceled state of the dispatcher.
80e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko   */
815a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko  bool IsCanceled() const;
825a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko
835a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko private:
845a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko  ServiceDispatcher();
855a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko
865a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko  // Internal thread accounting.
875a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko  int ThreadEnter();
885a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko  void ThreadExit();
895a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko
905a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko  std::mutex mutex_;
915a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko  std::condition_variable condition_;
925a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko  std::atomic<bool> canceled_{false};
935a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko
945a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko  std::vector<std::shared_ptr<Service>> services_;
955a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko
965a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko  int thread_count_ = 0;
975a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko  LocalHandle event_fd_;
985a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko  LocalHandle epoll_fd_;
995a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko
1005a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko  ServiceDispatcher(const ServiceDispatcher&) = delete;
1015a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko  void operator=(const ServiceDispatcher&) = delete;
102e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko};
103e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
104e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko}  // namespace pdx
105e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko}  // namespace android
106e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
107e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#endif  // ANDROID_PDX_SERVICE_DISPATCHER_H_
108