1f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle/*
2f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle * Copyright (C) 2010 The Android Open Source Project
3f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle *
4f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle * Licensed under the Apache License, Version 2.0 (the "License");
5f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle * you may not use this file except in compliance with the License.
6f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle * You may obtain a copy of the License at
7f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle *
8f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle *      http://www.apache.org/licenses/LICENSE-2.0
9f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle *
10f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle * Unless required by applicable law or agreed to in writing, software
11f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle * distributed under the License is distributed on an "AS IS" BASIS,
12f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle * See the License for the specific language governing permissions and
14f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle * limitations under the License.
15f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle */
16f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
17f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle#include <assert.h>
18f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle#include <errno.h>
19f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle#include <fcntl.h>
20f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle#include <unistd.h>
21f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle#include <utils.h>
22f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
23f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle#include "fdpool.h"
24f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
25f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle#define INVALID_FD (-1)
26f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle#define FDPOOL_SIZE 4
27f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
28f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttlestatic struct pooled_fd fdpool_head = {
29f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	.fd = INVALID_FD,
30f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	.prev = &fdpool_head,
31f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	.next = &fdpool_head
32f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle};
33f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttlestatic int fdpool_count = 0;
34f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
350cb61411eadd92b7202e045c1c9ec8df7fb636feThomas Tuttlestatic void fdpool_insert_head(struct pooled_fd *node)
360cb61411eadd92b7202e045c1c9ec8df7fb636feThomas Tuttle{
37f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	struct pooled_fd *prev = &fdpool_head;
38f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	struct pooled_fd *next = prev->next;
39f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
40f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	assert(node);
41f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
42f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	prev->next = node;
43f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	node->prev = prev;
44f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	node->next = next;
45f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	next->prev = node;
46f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
47f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	fdpool_count++;
48f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle}
49f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
500cb61411eadd92b7202e045c1c9ec8df7fb636feThomas Tuttlestatic void fdpool_remove(struct pooled_fd *node)
510cb61411eadd92b7202e045c1c9ec8df7fb636feThomas Tuttle{
52f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	struct pooled_fd *prev = node->prev;
53f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	struct pooled_fd *next = node->next;
54f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
55f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	assert(prev);
56f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	assert(next);
57f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
58f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	prev->next = next;
59f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	next->prev = prev;
60f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
61f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	fdpool_count--;
62f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle}
63f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
640cb61411eadd92b7202e045c1c9ec8df7fb636feThomas Tuttlestatic struct pooled_fd *fdpool_remove_tail(void)
650cb61411eadd92b7202e045c1c9ec8df7fb636feThomas Tuttle{
66f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	struct pooled_fd *tail = fdpool_head.prev;
67f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
68f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	assert(tail != &fdpool_head);
69f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
70f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	fdpool_remove(tail);
71f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
72f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	return tail;
73f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle}
74f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
750cb61411eadd92b7202e045c1c9ec8df7fb636feThomas Tuttlestatic void fdpool_clear(struct pooled_fd *pfd)
760cb61411eadd92b7202e045c1c9ec8df7fb636feThomas Tuttle{
77f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	assert(pfd);
78f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
79f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	pfd->fd = INVALID_FD;
80f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	pfd->prev = pfd->next = NULL;
81f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle}
82f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
830cb61411eadd92b7202e045c1c9ec8df7fb636feThomas Tuttlestatic void fdpool_unpool(struct pooled_fd *pfd)
840cb61411eadd92b7202e045c1c9ec8df7fb636feThomas Tuttle{
85f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	close(pfd->fd);
86f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	fdpool_clear(pfd);
87f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle}
88f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
890cb61411eadd92b7202e045c1c9ec8df7fb636feThomas Tuttlestatic void fdpool_evict(void)
900cb61411eadd92b7202e045c1c9ec8df7fb636feThomas Tuttle{
91f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	struct pooled_fd *tail;
92f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
93f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	tail = fdpool_remove_tail();
94f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	fdpool_unpool(tail);
95f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle}
96f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
970cb61411eadd92b7202e045c1c9ec8df7fb636feThomas Tuttlestatic void fdpool_pool(struct pooled_fd *pfd, int fd)
980cb61411eadd92b7202e045c1c9ec8df7fb636feThomas Tuttle{
99f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	if (fdpool_count >= FDPOOL_SIZE)
100f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle		fdpool_evict();
101f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
102f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	fdpool_insert_head(pfd);
103f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	pfd->fd = fd;
104f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle}
105f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
1060cb61411eadd92b7202e045c1c9ec8df7fb636feThomas Tuttlestatic void fdpool_touch(struct pooled_fd *pfd)
1070cb61411eadd92b7202e045c1c9ec8df7fb636feThomas Tuttle{
108f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	fdpool_remove(pfd);
109f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	fdpool_insert_head(pfd);
110f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle}
111f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
112f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
113f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
1140cb61411eadd92b7202e045c1c9ec8df7fb636feThomas Tuttlevoid fdpool_init(struct pooled_fd *pfd)
1150cb61411eadd92b7202e045c1c9ec8df7fb636feThomas Tuttle{
116f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	fdpool_clear(pfd);
117f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle}
118f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
1190cb61411eadd92b7202e045c1c9ec8df7fb636feThomas Tuttleint fdpool_open(struct pooled_fd *pfd, const char *pathname, int flags)
1200cb61411eadd92b7202e045c1c9ec8df7fb636feThomas Tuttle{
121f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	int open_errno;
122f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	int fd;
123f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
124f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	if (pfd->fd != INVALID_FD) {
125f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle		fdpool_touch(pfd);
126f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle		return pfd->fd;
127f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	}
128f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
129f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	fd = open(pathname, flags);
130f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	open_errno = errno;
131f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
132f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	if (fd >= 0) {
133f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle		fdpool_pool(pfd, fd);
134f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	}
135f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
136f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	errno = open_errno;
137f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	return fd;
138f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle}
139f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
1400cb61411eadd92b7202e045c1c9ec8df7fb636feThomas Tuttlevoid fdpool_close(struct pooled_fd *pfd)
1410cb61411eadd92b7202e045c1c9ec8df7fb636feThomas Tuttle{
142f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	assert(pfd);
143f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle
144f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle	fdpool_unpool(pfd);
145f79b2dff1024db4f6326f3422236bed169dd902fThomas Tuttle}
146