1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef HIDL_EVENTFLAG_H
18#define HIDL_EVENTFLAG_H
19
20#include <time.h>
21#include <utils/Errors.h>
22#include <atomic>
23
24namespace android {
25namespace hardware {
26
27/**
28 * EventFlag is an abstraction that application code utilizing FMQ can use to wait on
29 * conditions like full, empty, data available etc. The same EventFlag object
30 * can be used with multiple FMQs.
31 */
32struct EventFlag {
33    /**
34     * Create an event flag object with mapping information.
35     *
36     * @param fd File descriptor to be mmapped to create the event flag word.
37     * There is no transfer of ownership of the fd. The caller will still
38     * own the fd for the purpose of closing it.
39     * @param offset Offset parameter to mmap.
40     * @param ef Pointer to address of the EventFlag object that gets created. Will be set to
41     * nullptr if unsuccesful.
42     *
43     * @return status Returns a status_t error code. Likely error codes are
44     * NO_ERROR if the method is successful or BAD_VALUE due to invalid
45     * mapping arguments.
46     */
47    static status_t createEventFlag(int fd, off_t offset, EventFlag** ef);
48
49    /**
50     * Create an event flag object from the address of the flag word.
51     *
52     * @param  efWordPtr Pointer to the event flag word.
53     * @param status Returns a status_t error code. Likely error codes are
54     * NO_ERROR if the method is successful or BAD_VALUE if efWordPtr is a null
55     * pointer.
56     * @param ef Pointer to the address of the EventFlag object that gets created. Will be set to
57     * nullptr if unsuccesful.
58     *
59     * @return Returns a status_t error code. Likely error codes are
60     * NO_ERROR if the method is successful or BAD_VALUE if efAddr is a null
61     * pointer.
62     *
63     */
64    static status_t createEventFlag(std::atomic<uint32_t>* efWordPtr,
65                                    EventFlag** ef);
66
67    /**
68     * Delete an EventFlag object.
69     *
70     * @param ef A double pointer to the EventFlag object to be destroyed.
71     *
72     * @return Returns a status_t error code. Likely error codes are
73     * NO_ERROR if the method is successful or BAD_VALUE due to
74     * a bad input parameter.
75     */
76    static status_t deleteEventFlag(EventFlag** ef);
77
78    /**
79     * Set the specified bits of the event flag word here and wake up a thread.
80     * @param bitmask The bits to be set on the event flag word.
81     *
82     * @return Returns a status_t error code. Likely error codes are
83     * NO_ERROR if the method is successful or BAD_VALUE if the bit mask
84     * does not have any bits set.
85     */
86    status_t wake(uint32_t bitmask);
87
88    /**
89     * Wait for any of the bits in the bit mask to be set.
90     *
91     * @param bitmask The bits to wait on.
92     * @param timeoutNanoSeconds Specifies timeout duration in nanoseconds. It is converted to
93     * an absolute timeout for the wait according to the CLOCK_MONOTONIC clock.
94     * @param efState The event flag bits that caused the return from wake.
95     * @param retry If true, retry automatically for a spurious wake. If false,
96     * will return -EINTR or -EAGAIN for a spurious wake.
97     *
98     * @return Returns a status_t error code. Likely error codes are
99     * NO_ERROR if the method is successful, BAD_VALUE due to bad input
100     * parameters, TIMED_OUT if the wait timedout as per the timeout
101     * parameter, -EAGAIN or -EINTR to indicate that the caller needs to invoke
102     * wait() again. -EAGAIN or -EINTR error codes will not be returned if
103     * 'retry' is true since the method will retry waiting in that case.
104     */
105    status_t wait(uint32_t bitmask,
106                  uint32_t* efState,
107                  int64_t timeOutNanoSeconds = 0,
108                  bool retry = false);
109private:
110    bool mEfWordNeedsUnmapping = false;
111    std::atomic<uint32_t>* mEfWordPtr = nullptr;
112
113    /*
114     * mmap memory for the event flag word.
115     */
116    EventFlag(int fd, off_t offset, status_t* status);
117
118    /*
119     * Use this constructor if we already know where the event flag word
120     * lives.
121     */
122    EventFlag(std::atomic<uint32_t>* efWordPtr, status_t* status);
123
124    /*
125     * Disallow constructor without argument and copying.
126     */
127    EventFlag();
128    EventFlag& operator=(const EventFlag& other) = delete;
129    EventFlag(const EventFlag& other) = delete;
130
131    /*
132     * Wait for any of the bits in the bit mask to be set.
133     */
134    status_t waitHelper(uint32_t bitmask, uint32_t* efState, int64_t timeOutNanoSeconds);
135
136    /*
137     * Utility method to unmap the event flag word.
138     */
139    static status_t unmapEventFlagWord(std::atomic<uint32_t>* efWordPtr,
140                                       bool* efWordNeedsUnmapping);
141
142    /*
143     * Utility method to convert timeout duration to an absolute CLOCK_MONOTONIC
144     * clock time which is required by futex syscalls.
145     */
146    inline void addNanosecondsToCurrentTime(int64_t nanoseconds, struct timespec* timeAbs);
147    ~EventFlag();
148};
149}  // namespace hardware
150}  // namespace android
151#endif
152