fdpool.c revision f79b2dff1024db4f6326f3422236bed169dd902f
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	struct pooled_fd *prev = &fdpool_head;
37	struct pooled_fd *next = prev->next;
38
39	assert(node);
40
41	prev->next = node;
42	node->prev = prev;
43	node->next = next;
44	next->prev = node;
45
46	fdpool_count++;
47}
48
49static void fdpool_remove(struct pooled_fd *node) {
50	struct pooled_fd *prev = node->prev;
51	struct pooled_fd *next = node->next;
52
53	assert(prev);
54	assert(next);
55
56	prev->next = next;
57	next->prev = prev;
58
59	fdpool_count--;
60}
61
62static struct pooled_fd *fdpool_remove_tail(void) {
63	struct pooled_fd *tail = fdpool_head.prev;
64
65	assert(tail != &fdpool_head);
66
67	fdpool_remove(tail);
68
69	return tail;
70}
71
72static void fdpool_clear(struct pooled_fd *pfd) {
73	assert(pfd);
74
75	pfd->fd = INVALID_FD;
76	pfd->prev = pfd->next = NULL;
77}
78
79static void fdpool_unpool(struct pooled_fd *pfd) {
80	close(pfd->fd);
81	fdpool_clear(pfd);
82}
83
84static void fdpool_evict(void) {
85	struct pooled_fd *tail;
86
87	tail = fdpool_remove_tail();
88	fdpool_unpool(tail);
89}
90
91static void fdpool_pool(struct pooled_fd *pfd, int fd) {
92	if (fdpool_count >= FDPOOL_SIZE)
93		fdpool_evict();
94
95	fdpool_insert_head(pfd);
96	pfd->fd = fd;
97}
98
99static void fdpool_touch(struct pooled_fd *pfd) {
100	fdpool_remove(pfd);
101	fdpool_insert_head(pfd);
102}
103
104
105
106void fdpool_init(struct pooled_fd *pfd) {
107	fdpool_clear(pfd);
108}
109
110int fdpool_open(struct pooled_fd *pfd, const char *pathname, int flags) {
111	int open_errno;
112	int fd;
113
114	if (pfd->fd != INVALID_FD) {
115		fdpool_touch(pfd);
116		return pfd->fd;
117	}
118
119	fd = open(pathname, flags);
120	open_errno = errno;
121
122	if (fd >= 0) {
123		fdpool_pool(pfd, fd);
124	}
125
126	errno = open_errno;
127	return fd;
128}
129
130void fdpool_close(struct pooled_fd *pfd) {
131	assert(pfd);
132
133	fdpool_unpool(pfd);
134}
135