fdpool.c revision f79b2dff1024db4f6326f3422236bed169dd902f
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 struct pooled_fd *prev = &fdpool_head; 37 struct pooled_fd *next = prev->next; 38 39 assert(node); 40 41 prev->next = node; 42 node->prev = prev; 43 node->next = next; 44 next->prev = node; 45 46 fdpool_count++; 47} 48 49static void fdpool_remove(struct pooled_fd *node) { 50 struct pooled_fd *prev = node->prev; 51 struct pooled_fd *next = node->next; 52 53 assert(prev); 54 assert(next); 55 56 prev->next = next; 57 next->prev = prev; 58 59 fdpool_count--; 60} 61 62static struct pooled_fd *fdpool_remove_tail(void) { 63 struct pooled_fd *tail = fdpool_head.prev; 64 65 assert(tail != &fdpool_head); 66 67 fdpool_remove(tail); 68 69 return tail; 70} 71 72static void fdpool_clear(struct pooled_fd *pfd) { 73 assert(pfd); 74 75 pfd->fd = INVALID_FD; 76 pfd->prev = pfd->next = NULL; 77} 78 79static void fdpool_unpool(struct pooled_fd *pfd) { 80 close(pfd->fd); 81 fdpool_clear(pfd); 82} 83 84static void fdpool_evict(void) { 85 struct pooled_fd *tail; 86 87 tail = fdpool_remove_tail(); 88 fdpool_unpool(tail); 89} 90 91static void fdpool_pool(struct pooled_fd *pfd, int fd) { 92 if (fdpool_count >= FDPOOL_SIZE) 93 fdpool_evict(); 94 95 fdpool_insert_head(pfd); 96 pfd->fd = fd; 97} 98 99static void fdpool_touch(struct pooled_fd *pfd) { 100 fdpool_remove(pfd); 101 fdpool_insert_head(pfd); 102} 103 104 105 106void fdpool_init(struct pooled_fd *pfd) { 107 fdpool_clear(pfd); 108} 109 110int fdpool_open(struct pooled_fd *pfd, const char *pathname, int flags) { 111 int open_errno; 112 int fd; 113 114 if (pfd->fd != INVALID_FD) { 115 fdpool_touch(pfd); 116 return pfd->fd; 117 } 118 119 fd = open(pathname, flags); 120 open_errno = errno; 121 122 if (fd >= 0) { 123 fdpool_pool(pfd, fd); 124 } 125 126 errno = open_errno; 127 return fd; 128} 129 130void fdpool_close(struct pooled_fd *pfd) { 131 assert(pfd); 132 133 fdpool_unpool(pfd); 134} 135