Home | History | Annotate | Download | only in fatblock
      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