blob: d43189b5d79f9f16b0647f8be82397940d3dce6d [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed 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 "filesystem_notifier.h"
#include <limits.h>
#include <poll.h>
#include <sys/inotify.h>
#include <sys/ioctl.h>
#include <unistd.h>
namespace profiler {
// This array must be kep in sync with notifier.h enum "events".
int event_translation_table[] = {
IN_CLOSE, // CLOSE
};
FileSystemNotifier::FileSystemNotifier(const std::string &path,
uint32_t event_mask)
: path_(path), file_descriptor_(-1), watch_descriptor_(-1) {
file_descriptor_ = inotify_init();
// Transform events to inotify events.
event_mask_ = TranslateMask(event_mask);
// Start watching for events contained in the event_mask_.
watch_descriptor_ =
inotify_add_watch(file_descriptor_, path_.c_str(), event_mask_);
}
uint32_t FileSystemNotifier::TranslateMask(uint32_t event_mask) {
uint64_t dst = 0;
int bit = 1;
for (int i = 0; i < sizeof(event_mask) * CHAR_BIT; i++) {
if (bit & event_mask) {
dst |= GetDstValue(static_cast<Event>(bit));
}
bit <<= 1;
}
return dst;
}
uint32_t FileSystemNotifier::GetDstValue(Event e) {
switch (e) {
case CLOSE:
return IN_CLOSE;
}
return 0;
}
bool FileSystemNotifier::IsReadyToNotify() { return watch_descriptor_ != -1; }
FileSystemNotifier::~FileSystemNotifier() {
inotify_rm_watch(file_descriptor_, watch_descriptor_);
close(file_descriptor_);
}
bool FileSystemNotifier::WaitUntilEventOccurs(int64_t timeout_ms) {
// Use a non-blocking poll system so it will timeout if the file never
// received the expected events.
struct pollfd pfd = {file_descriptor_, POLLIN, 0};
int ret = poll(&pfd, 1, timeout_ms);
if (ret < 0) {
return false;
}
// The events have been received. Time to read them.
unsigned int available_bytes;
ioctl(file_descriptor_, FIONREAD, &available_bytes);
int num_events = available_bytes / sizeof(struct inotify_event);
struct inotify_event events[num_events];
int length =
read(file_descriptor_, reinterpret_cast<char *>(events), sizeof(events));
if (length < 0) {
return false;
}
// Parse events.
for (int i = 0; i < num_events; i++) {
if (events[i].mask & event_mask_) {
// Found one of the expected events.
return true;
}
}
// This should never happen.
return false;
}
} // namespace profiler