• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
28 static struct pooled_fd fdpool_head = {
29 	.fd = INVALID_FD,
30 	.prev = &fdpool_head,
31 	.next = &fdpool_head
32 };
33 static int fdpool_count = 0;
34 
fdpool_insert_head(struct pooled_fd * node)35 static 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 
fdpool_remove(struct pooled_fd * node)50 static 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 
fdpool_remove_tail(void)64 static 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 
fdpool_clear(struct pooled_fd * pfd)75 static 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 
fdpool_unpool(struct pooled_fd * pfd)83 static void fdpool_unpool(struct pooled_fd *pfd)
84 {
85 	close(pfd->fd);
86 	fdpool_clear(pfd);
87 }
88 
fdpool_evict(void)89 static void fdpool_evict(void)
90 {
91 	struct pooled_fd *tail;
92 
93 	tail = fdpool_remove_tail();
94 	fdpool_unpool(tail);
95 }
96 
fdpool_pool(struct pooled_fd * pfd,int fd)97 static 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 
fdpool_touch(struct pooled_fd * pfd)106 static void fdpool_touch(struct pooled_fd *pfd)
107 {
108 	fdpool_remove(pfd);
109 	fdpool_insert_head(pfd);
110 }
111 
112 
113 
fdpool_init(struct pooled_fd * pfd)114 void fdpool_init(struct pooled_fd *pfd)
115 {
116 	fdpool_clear(pfd);
117 }
118 
fdpool_open(struct pooled_fd * pfd,const char * pathname,int flags)119 int 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 
fdpool_close(struct pooled_fd * pfd)140 void fdpool_close(struct pooled_fd *pfd)
141 {
142 	assert(pfd);
143 
144 	fdpool_unpool(pfd);
145 }
146