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{ 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 50static 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 64static 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 75static 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 83static void fdpool_unpool(struct pooled_fd *pfd) 84{ 85 close(pfd->fd); 86 fdpool_clear(pfd); 87} 88 89static void fdpool_evict(void) 90{ 91 struct pooled_fd *tail; 92 93 tail = fdpool_remove_tail(); 94 fdpool_unpool(tail); 95} 96 97static 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 106static void fdpool_touch(struct pooled_fd *pfd) 107{ 108 fdpool_remove(pfd); 109 fdpool_insert_head(pfd); 110} 111 112 113 114void fdpool_init(struct pooled_fd *pfd) 115{ 116 fdpool_clear(pfd); 117} 118 119int 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 140void fdpool_close(struct pooled_fd *pfd) 141{ 142 assert(pfd); 143 144 fdpool_unpool(pfd); 145} 146