1487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang/*
2487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang * Copyright (C) 2016 The Android Open Source Project
3487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang *
4487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang * Licensed under the Apache License, Version 2.0 (the "License");
5487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang * you may not use this file except in compliance with the License.
6487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang * You may obtain a copy of the License at
7487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang *
8487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang *      http://www.apache.org/licenses/LICENSE-2.0
9487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang *
10487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang * Unless required by applicable law or agreed to in writing, software
11487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang * distributed under the License is distributed on an "AS IS" BASIS,
12487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang * See the License for the specific language governing permissions and
14487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang * limitations under the License.
15487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang */
16487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
17487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang#include <android-base/logging.h>
18487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang#include <condition_variable>
19487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang#include <memory>
20487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang#include <mutex>
21487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang#include <queue>
22487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
23487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang#include "AsyncIO.h"
24487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
25487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangnamespace {
26487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
27487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangvoid read_func(struct aiocb *aiocbp) {
28487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    aiocbp->ret = TEMP_FAILURE_RETRY(pread(aiocbp->aio_fildes,
29487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang                aiocbp->aio_buf, aiocbp->aio_nbytes, aiocbp->aio_offset));
30487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    if (aiocbp->ret == -1) aiocbp->error = errno;
31487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang}
32487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
33487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangvoid write_func(struct aiocb *aiocbp) {
34487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    aiocbp->ret = TEMP_FAILURE_RETRY(pwrite(aiocbp->aio_fildes,
35487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang                aiocbp->aio_buf, aiocbp->aio_nbytes, aiocbp->aio_offset));
36487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    if (aiocbp->ret == -1) aiocbp->error = errno;
37487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang}
38487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
39487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangvoid splice_read_func(struct aiocb *aiocbp) {
408e889ef487c1adb3a5a02ff41712fbca44fd449fJerry Zhang    loff_t long_offset = aiocbp->aio_offset;
41487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    aiocbp->ret = TEMP_FAILURE_RETRY(splice(aiocbp->aio_fildes,
428e889ef487c1adb3a5a02ff41712fbca44fd449fJerry Zhang                &long_offset, aiocbp->aio_sink,
43487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang                NULL, aiocbp->aio_nbytes, 0));
44487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    if (aiocbp->ret == -1) aiocbp->error = errno;
45487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang}
46487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
47487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangvoid splice_write_func(struct aiocb *aiocbp) {
488e889ef487c1adb3a5a02ff41712fbca44fd449fJerry Zhang    loff_t long_offset = aiocbp->aio_offset;
49487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    aiocbp->ret = TEMP_FAILURE_RETRY(splice(aiocbp->aio_fildes, NULL,
508e889ef487c1adb3a5a02ff41712fbca44fd449fJerry Zhang                aiocbp->aio_sink, &long_offset,
51487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang                aiocbp->aio_nbytes, 0));
52487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    if (aiocbp->ret == -1) aiocbp->error = errno;
53487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang}
54487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
55487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangstd::queue<std::unique_ptr<struct aiocb>> queue;
56487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangstd::mutex queue_lock;
57487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangstd::condition_variable queue_cond;
58487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangstd::condition_variable write_cond;
59487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangint done = 1;
60487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangvoid splice_write_pool_func(int) {
61487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    while(1) {
62487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        std::unique_lock<std::mutex> lk(queue_lock);
63487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        queue_cond.wait(lk, []{return !queue.empty() || done;});
64487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        if (queue.empty() && done) {
65487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang            return;
66487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        }
67487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        std::unique_ptr<struct aiocb> aiocbp = std::move(queue.front());
68487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        queue.pop();
69487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        lk.unlock();
70487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        write_cond.notify_one();
71487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        splice_write_func(aiocbp.get());
72487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        close(aiocbp->aio_fildes);
73487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    }
74487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang}
75487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
76487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangvoid write_pool_func(int) {
77487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    while(1) {
78487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        std::unique_lock<std::mutex> lk(queue_lock);
79487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        queue_cond.wait(lk, []{return !queue.empty() || done;});
80487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        if (queue.empty() && done) {
81487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang            return;
82487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        }
83487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        std::unique_ptr<struct aiocb> aiocbp = std::move(queue.front());
84487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        queue.pop();
85487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        lk.unlock();
86487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        write_cond.notify_one();
87487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        aiocbp->ret = TEMP_FAILURE_RETRY(pwrite(aiocbp->aio_fildes,
88487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang                    aiocbp->aio_pool_buf.get(), aiocbp->aio_nbytes, aiocbp->aio_offset));
89487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        if (aiocbp->ret == -1) aiocbp->error = errno;
90487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    }
91487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang}
92487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
93487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangconstexpr int NUM_THREADS = 1;
94487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangconstexpr int MAX_QUEUE_SIZE = 10;
95487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangstd::thread pool[NUM_THREADS];
96487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
97487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang} // end anonymous namespace
98487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
997063c936e50326883e672837036381f77080c2f3Jerry Zhangaiocb::~aiocb() {
1007063c936e50326883e672837036381f77080c2f3Jerry Zhang    CHECK(!thread.joinable());
1017063c936e50326883e672837036381f77080c2f3Jerry Zhang}
1027063c936e50326883e672837036381f77080c2f3Jerry Zhang
103487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangvoid aio_pool_init(void(f)(int)) {
104487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    CHECK(done == 1);
105487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    done = 0;
106487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    for (int i = 0; i < NUM_THREADS; i++) {
107487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        pool[i] = std::thread(f, i);
108487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    }
109487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang}
110487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
111487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangvoid aio_pool_splice_init() {
112487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    aio_pool_init(splice_write_pool_func);
113487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang}
114487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
115487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangvoid aio_pool_write_init() {
116487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    aio_pool_init(write_pool_func);
117487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang}
118487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
119487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangvoid aio_pool_end() {
120487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    done = 1;
121487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    for (int i = 0; i < NUM_THREADS; i++) {
122487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        std::unique_lock<std::mutex> lk(queue_lock);
123487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        lk.unlock();
124487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        queue_cond.notify_one();
125487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    }
126487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
127487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    for (int i = 0; i < NUM_THREADS; i++) {
128487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        pool[i].join();
129487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    }
130487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang}
131487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
132487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang// used for both writes and splices depending on which init was used before.
133487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangint aio_pool_write(struct aiocb *aiocbp) {
134487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    std::unique_lock<std::mutex> lk(queue_lock);
135487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    write_cond.wait(lk, []{return queue.size() < MAX_QUEUE_SIZE;});
136487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    queue.push(std::unique_ptr<struct aiocb>(aiocbp));
137487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    lk.unlock();
138487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    queue_cond.notify_one();
139487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    return 0;
140487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang}
141487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
142487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangint aio_read(struct aiocb *aiocbp) {
143487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    aiocbp->thread = std::thread(read_func, aiocbp);
144487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    return 0;
145487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang}
146487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
147487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangint aio_write(struct aiocb *aiocbp) {
148487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    aiocbp->thread = std::thread(write_func, aiocbp);
149487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    return 0;
150487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang}
151487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
152487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangint aio_splice_read(struct aiocb *aiocbp) {
153487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    aiocbp->thread = std::thread(splice_read_func, aiocbp);
154487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    return 0;
155487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang}
156487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
157487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangint aio_splice_write(struct aiocb *aiocbp) {
158487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    aiocbp->thread = std::thread(splice_write_func, aiocbp);
159487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    return 0;
160487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang}
161487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
162487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangint aio_error(const struct aiocb *aiocbp) {
163487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    return aiocbp->error;
164487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang}
165487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
166487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangssize_t aio_return(struct aiocb *aiocbp) {
167487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    return aiocbp->ret;
168487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang}
169487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
170487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangint aio_suspend(struct aiocb *aiocbp[], int n,
171487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        const struct timespec *) {
172487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    for (int i = 0; i < n; i++) {
173487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang        aiocbp[i]->thread.join();
174487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    }
175487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    return 0;
176487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang}
177487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
178487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhangint aio_cancel(int, struct aiocb *) {
179487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    // Not implemented
180487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang    return -1;
181487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang}
182487be61fb0a38873aec1d12da92437fba5e728f2Jerry Zhang
183