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 } 146