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