| /** @file |
| |
| A brief file description |
| |
| @section license License |
| |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| /************************************************************************** |
| EventNotify.cc |
| |
| Generic event notify mechanism among threads. |
| **************************************************************************/ |
| |
| #include "tscore/EventNotify.h" |
| #include "tscore/ink_hrtime.h" |
| #include "tscore/ink_defs.h" |
| |
| #ifdef HAVE_EVENTFD |
| #include <sys/eventfd.h> |
| #include <fcntl.h> |
| #include <sys/epoll.h> |
| #endif |
| |
| EventNotify::EventNotify() |
| { |
| #ifdef HAVE_EVENTFD |
| int ret; |
| struct epoll_event ev; |
| |
| m_event_fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); |
| ink_release_assert(m_event_fd != -1); |
| |
| ev.events = EPOLLIN; |
| ev.data.fd = m_event_fd; |
| |
| m_epoll_fd = epoll_create(1); |
| ink_release_assert(m_epoll_fd != -1); |
| |
| ret = epoll_ctl(m_epoll_fd, EPOLL_CTL_ADD, m_event_fd, &ev); |
| ink_release_assert(ret != -1); |
| #else |
| ink_cond_init(&m_cond); |
| ink_mutex_init(&m_mutex); |
| #endif |
| } |
| |
| void |
| EventNotify::signal() |
| { |
| #ifdef HAVE_EVENTFD |
| uint64_t value = 1; |
| // |
| // If the addition would cause the counter’s value of eventfd |
| // to exceed the maximum, write() will fail with the errno EAGAIN, |
| // which is acceptable as the receiver will be notified eventually. |
| // |
| ATS_UNUSED_RETURN(write(m_event_fd, &value, sizeof(uint64_t))); |
| #else |
| ink_cond_signal(&m_cond); |
| #endif |
| } |
| |
| int |
| EventNotify::wait() |
| { |
| #ifdef HAVE_EVENTFD |
| ssize_t nr, nr_fd; |
| uint64_t value = 0; |
| struct epoll_event ev; |
| |
| do { |
| nr_fd = epoll_wait(m_epoll_fd, &ev, 1, 500000); |
| } while (nr_fd == -1 && errno == EINTR); |
| |
| if (nr_fd == -1) { |
| return errno; |
| } |
| |
| nr = read(m_event_fd, &value, sizeof(uint64_t)); |
| if (nr == sizeof(uint64_t)) { |
| return 0; |
| } else { |
| return errno; |
| } |
| #else |
| ink_cond_wait(&m_cond, &m_mutex); |
| return 0; |
| #endif |
| } |
| |
| int |
| EventNotify::timedwait(int timeout) // milliseconds |
| { |
| #ifdef HAVE_EVENTFD |
| ssize_t nr, nr_fd = 0; |
| uint64_t value = 0; |
| struct epoll_event ev; |
| |
| // |
| // When timeout < 0, epoll_wait() will wait indefinitely, but |
| // pthread_cond_timedwait() will return ETIMEDOUT immediately. |
| // We should keep compatible with pthread_cond_timedwait() here. |
| // |
| if (timeout < 0) { |
| return ETIMEDOUT; |
| } |
| |
| do { |
| nr_fd = epoll_wait(m_epoll_fd, &ev, 1, timeout); |
| } while (nr_fd == -1 && errno == EINTR); |
| |
| if (nr_fd == 0) { |
| return ETIMEDOUT; |
| } else if (nr_fd == -1) { |
| return errno; |
| } |
| |
| nr = read(m_event_fd, &value, sizeof(uint64_t)); |
| if (nr == sizeof(uint64_t)) { |
| return 0; |
| } else { |
| return errno; |
| } |
| #else |
| ink_timestruc abstime; |
| |
| abstime = ink_hrtime_to_timespec(ink_get_hrtime_internal() + HRTIME_SECONDS(timeout)); |
| return ink_cond_timedwait(&m_cond, &m_mutex, &abstime); |
| #endif |
| } |
| |
| void |
| EventNotify::lock() |
| { |
| #ifdef HAVE_EVENTFD |
| // do nothing |
| #else |
| ink_mutex_acquire(&m_mutex); |
| #endif |
| } |
| |
| bool |
| EventNotify::trylock() |
| { |
| #ifdef HAVE_EVENTFD |
| return true; |
| #else |
| return ink_mutex_try_acquire(&m_mutex); |
| #endif |
| } |
| |
| void |
| EventNotify::unlock() |
| { |
| #ifdef HAVE_EVENTFD |
| // do nothing |
| #else |
| ink_mutex_release(&m_mutex); |
| #endif |
| } |
| |
| EventNotify::~EventNotify() |
| { |
| #ifdef HAVE_EVENTFD |
| close(m_event_fd); |
| close(m_epoll_fd); |
| #else |
| ink_cond_destroy(&m_cond); |
| ink_mutex_destroy(&m_mutex); |
| #endif |
| } |