]> git.proxmox.com Git - mirror_ovs.git/blame - lib/async-append-aio.c
python: Update build system to ensure dirs.py is created.
[mirror_ovs.git] / lib / async-append-aio.c
CommitLineData
97eba8fc
BP
1/* Copyright (c) 2013 Nicira, Inc.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <config.h>
17
18/* This implementation of the async-append.h interface uses the POSIX
19 * asynchronous I/O interface. */
20
21#include "async-append.h"
22
23#include <aio.h>
24#include <errno.h>
25#include <stdlib.h>
26#include <unistd.h>
27
28#include "byteq.h"
29#include "ovs-thread.h"
30#include "util.h"
31
32/* Maximum number of bytes of buffered data. */
33enum { BUFFER_SIZE = 65536 };
34
35/* Maximum number of aiocbs to use.
36 *
37 * aiocbs are big (144 bytes with glibc 2.11 on i386) so we try to allow for a
38 * reasonable number by basing the number we allocate on the amount of buffer
39 * space. */
40enum { MAX_CBS = ROUND_DOWN_POW2(BUFFER_SIZE / sizeof(struct aiocb)) };
41BUILD_ASSERT_DECL(IS_POW2(MAX_CBS));
42
43struct async_append {
44 int fd;
45
46 struct aiocb *aiocbs;
47 unsigned int aiocb_head, aiocb_tail;
48
49 uint8_t *buffer;
50 struct byteq byteq;
51};
52
97eba8fc
BP
53struct async_append *
54async_append_create(int fd)
55{
56 struct async_append *ap;
57
58 ap = xmalloc(sizeof *ap);
59 ap->fd = fd;
60 ap->aiocbs = xmalloc(MAX_CBS * sizeof *ap->aiocbs);
61 ap->aiocb_head = ap->aiocb_tail = 0;
62 ap->buffer = xmalloc(BUFFER_SIZE);
63 byteq_init(&ap->byteq, ap->buffer, BUFFER_SIZE);
64
65 return ap;
66}
67
68void
69async_append_destroy(struct async_append *ap)
70{
71 if (ap) {
72 async_append_flush(ap);
73 free(ap->aiocbs);
74 free(ap->buffer);
75 free(ap);
76 }
77}
78
79static bool
80async_append_is_full(const struct async_append *ap)
81{
82 return (ap->aiocb_head - ap->aiocb_tail >= MAX_CBS
83 || byteq_is_full(&ap->byteq));
84}
85
86static bool
87async_append_is_empty(const struct async_append *ap)
88{
89 return byteq_is_empty(&ap->byteq);
90}
91
92static void
93async_append_wait(struct async_append *ap)
94{
95 int n = 0;
96
97 while (!async_append_is_empty(ap)) {
98 struct aiocb *aiocb = &ap->aiocbs[ap->aiocb_tail & (MAX_CBS - 1)];
99 int error = aio_error(aiocb);
100
101 if (error == EINPROGRESS) {
102 const struct aiocb *p = aiocb;
103 if (n > 0) {
104 return;
105 }
106 aio_suspend(&p, 1, NULL);
107 } else {
108 ignore(aio_return(aiocb));
109 ap->aiocb_tail++;
110 byteq_advance_tail(&ap->byteq, aiocb->aio_nbytes);
111 n++;
112 }
113 }
114}
115
116void
117async_append_write(struct async_append *ap, const void *data_, size_t size)
118{
119 const uint8_t *data = data_;
120
97eba8fc
BP
121 while (size > 0) {
122 struct aiocb *aiocb;
123 size_t chunk_size;
124 void *chunk;
125
126 while (async_append_is_full(ap)) {
127 async_append_wait(ap);
128 }
129
130 chunk = byteq_head(&ap->byteq);
131 chunk_size = byteq_headroom(&ap->byteq);
132 if (chunk_size > size) {
133 chunk_size = size;
134 }
135 memcpy(chunk, data, chunk_size);
136
137 aiocb = &ap->aiocbs[ap->aiocb_head & (MAX_CBS - 1)];
138 memset(aiocb, 0, sizeof *aiocb);
139 aiocb->aio_fildes = ap->fd;
140 aiocb->aio_offset = 0;
141 aiocb->aio_buf = chunk;
142 aiocb->aio_nbytes = chunk_size;
143 aiocb->aio_sigevent.sigev_notify = SIGEV_NONE;
144 if (aio_write(aiocb) == -1) {
145 async_append_flush(ap);
146 ignore(write(ap->fd, data, size));
147 return;
148 }
149
150 data += chunk_size;
151 size -= chunk_size;
152 byteq_advance_head(&ap->byteq, chunk_size);
153 ap->aiocb_head++;
154 }
155}
156
157void
158async_append_flush(struct async_append *ap)
159{
160 while (!async_append_is_empty(ap)) {
161 async_append_wait(ap);
162 }
163}