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