blob: 28ff1267545f7236888439d9c0bb61bedc6c8c8c [file] [log] [blame]
// 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.
#include "plasma/events.h"
#include <utility>
#include <errno.h>
extern "C" {
#include "plasma/thirdparty/ae/ae.h"
}
namespace plasma {
// Verify that the constants defined in events.h are defined correctly.
static_assert(kEventLoopTimerDone == AE_NOMORE, "constant defined incorrectly");
static_assert(kEventLoopOk == AE_OK, "constant defined incorrectly");
static_assert(kEventLoopRead == AE_READABLE, "constant defined incorrectly");
static_assert(kEventLoopWrite == AE_WRITABLE, "constant defined incorrectly");
void EventLoop::FileEventCallback(aeEventLoop* loop, int fd, void* context, int events) {
FileCallback* callback = reinterpret_cast<FileCallback*>(context);
(*callback)(events);
}
int EventLoop::TimerEventCallback(aeEventLoop* loop, TimerID timer_id, void* context) {
TimerCallback* callback = reinterpret_cast<TimerCallback*>(context);
return (*callback)(timer_id);
}
constexpr int kInitialEventLoopSize = 1024;
EventLoop::EventLoop() { loop_ = aeCreateEventLoop(kInitialEventLoopSize); }
bool EventLoop::AddFileEvent(int fd, int events, const FileCallback& callback) {
if (file_callbacks_.find(fd) != file_callbacks_.end()) {
return false;
}
auto data = std::unique_ptr<FileCallback>(new FileCallback(callback));
void* context = reinterpret_cast<void*>(data.get());
// Try to add the file descriptor.
int err = aeCreateFileEvent(loop_, fd, events, EventLoop::FileEventCallback, context);
// If it cannot be added, increase the size of the event loop.
if (err == AE_ERR && errno == ERANGE) {
err = aeResizeSetSize(loop_, 3 * aeGetSetSize(loop_) / 2);
if (err != AE_OK) {
return false;
}
err = aeCreateFileEvent(loop_, fd, events, EventLoop::FileEventCallback, context);
}
// In any case, test if there were errors.
if (err == AE_OK) {
file_callbacks_.emplace(fd, std::move(data));
return true;
}
return false;
}
void EventLoop::RemoveFileEvent(int fd) {
aeDeleteFileEvent(loop_, fd, AE_READABLE | AE_WRITABLE);
file_callbacks_.erase(fd);
}
void EventLoop::Start() { aeMain(loop_); }
void EventLoop::Stop() { aeStop(loop_); }
void EventLoop::Shutdown() {
if (loop_ != nullptr) {
aeDeleteEventLoop(loop_);
loop_ = nullptr;
}
}
EventLoop::~EventLoop() { Shutdown(); }
int64_t EventLoop::AddTimer(int64_t timeout, const TimerCallback& callback) {
auto data = std::unique_ptr<TimerCallback>(new TimerCallback(callback));
void* context = reinterpret_cast<void*>(data.get());
int64_t timer_id =
aeCreateTimeEvent(loop_, timeout, EventLoop::TimerEventCallback, context, NULL);
timer_callbacks_.emplace(timer_id, std::move(data));
return timer_id;
}
int EventLoop::RemoveTimer(int64_t timer_id) {
int err = aeDeleteTimeEvent(loop_, timer_id);
timer_callbacks_.erase(timer_id);
return err;
}
} // namespace plasma