1/******************************************************************************
2 *
3 *  Copyright (C) 2014 Google, Inc.
4 *
5 *  Licensed under the Apache License, Version 2.0 (the "License");
6 *  you may not use this file except in compliance with the License.
7 *  You may obtain a copy of the License at:
8 *
9 *  http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 *
17 ******************************************************************************/
18
19#define LOG_TAG "osi_semaphore"
20
21#include <assert.h>
22#include <errno.h>
23#include <fcntl.h>
24#include <string.h>
25#include <sys/eventfd.h>
26#include <utils/Log.h>
27
28#include "semaphore.h"
29
30#if !defined(EFD_SEMAPHORE)
31#  define EFD_SEMAPHORE (1 << 0)
32#endif
33
34struct semaphore_t {
35  int fd;
36};
37
38semaphore_t *semaphore_new(unsigned int value) {
39  semaphore_t *ret = malloc(sizeof(semaphore_t));
40  if (ret) {
41    ret->fd = eventfd(value, EFD_SEMAPHORE);
42    if (ret->fd == -1) {
43      ALOGE("%s unable to allocate semaphore: %s", __func__, strerror(errno));
44      free(ret);
45      ret = NULL;
46    }
47  }
48  return ret;
49}
50
51void semaphore_free(semaphore_t *semaphore) {
52  if (semaphore->fd != -1)
53    close(semaphore->fd);
54  free(semaphore);
55}
56
57void semaphore_wait(semaphore_t *semaphore) {
58  assert(semaphore != NULL);
59  assert(semaphore->fd != -1);
60
61  uint64_t value;
62  if (eventfd_read(semaphore->fd, &value) == -1)
63    ALOGE("%s unable to wait on semaphore: %s", __func__, strerror(errno));
64}
65
66bool semaphore_try_wait(semaphore_t *semaphore) {
67  assert(semaphore != NULL);
68  assert(semaphore->fd != -1);
69
70  int flags = fcntl(semaphore->fd, F_GETFL);
71  if (flags == -1) {
72    ALOGE("%s unable to get flags for semaphore fd: %s", __func__, strerror(errno));
73    return false;
74  }
75  if (fcntl(semaphore->fd, F_SETFL, flags | O_NONBLOCK) == -1) {
76    ALOGE("%s unable to set O_NONBLOCK for semaphore fd: %s", __func__, strerror(errno));
77    return false;
78  }
79
80  eventfd_t value;
81  if (eventfd_read(semaphore->fd, &value) == -1)
82    return false;
83
84  if (fcntl(semaphore->fd, F_SETFL, flags) == -1)
85    ALOGE("%s unable to resetore flags for semaphore fd: %s", __func__, strerror(errno));
86  return true;
87}
88
89void semaphore_post(semaphore_t *semaphore) {
90  assert(semaphore != NULL);
91  assert(semaphore->fd != -1);
92
93  if (eventfd_write(semaphore->fd, 1ULL) == -1)
94    ALOGE("%s unable to post to semaphore: %s", __func__, strerror(errno));
95}
96
97int semaphore_get_fd(const semaphore_t *semaphore) {
98  assert(semaphore != NULL);
99  assert(semaphore->fd != -1);
100  return semaphore->fd;
101}
102