OSDN Git Service

libublock: Don't prelink.
[android-x86/system-extras.git] / fatblock / fdpool.c
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
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
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
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
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
83 static void fdpool_unpool(struct pooled_fd *pfd)
84 {
85         close(pfd->fd);
86         fdpool_clear(pfd);
87 }
88
89 static void fdpool_evict(void)
90 {
91         struct pooled_fd *tail;
92
93         tail = fdpool_remove_tail();
94         fdpool_unpool(tail);
95 }
96
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
106 static void fdpool_touch(struct pooled_fd *pfd)
107 {
108         fdpool_remove(pfd);
109         fdpool_insert_head(pfd);
110 }
111
112
113
114 void fdpool_init(struct pooled_fd *pfd)
115 {
116         fdpool_clear(pfd);
117 }
118
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
140 void fdpool_close(struct pooled_fd *pfd)
141 {
142         assert(pfd);
143
144         fdpool_unpool(pfd);
145 }