1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <strings.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <sys/mman.h>
7 #include <errno.h>
8 #include "mread.h"
9
mread_init(int fd)10 mread_handle_t mread_init(int fd)
11 {
12 struct stat s;
13 mread_handle_t h;
14
15 h=malloc(sizeof(struct mread_ctrl));
16
17 if (!h)
18 {
19 perror("malloc");
20 exit(1);
21 }
22
23 bzero(h, sizeof(struct mread_ctrl));
24
25 h->fd = fd;
26
27 fstat(fd, &s);
28 h->file_size = s.st_size;
29
30 return h;
31 }
32
mread64(mread_handle_t h,void * rec,ssize_t len,off_t offset)33 ssize_t mread64(mread_handle_t h, void *rec, ssize_t len, off_t offset)
34 {
35 /* Idea: have a "cache" of N mmaped regions. If the offset is
36 * in one of the regions, just copy it. If not, evict one of the
37 * regions and map the appropriate range.
38 *
39 * Basic algorithm:
40 * - See if the offset is in one of the regions
41 * - If not, map it
42 * - evict an old region
43 * - map the new region
44 * - Copy
45 */
46 char * b=NULL;
47 int bind=-1;
48 off_t boffset=0;
49 ssize_t bsize;
50
51 #define dprintf(x...)
52 //#define dprintf fprintf
53
54 dprintf(warn, "%s: offset %llx len %d\n", __func__,
55 offset, len);
56 if ( offset > h->file_size )
57 {
58 dprintf(warn, " offset > file size %llx, returning 0\n",
59 h->file_size);
60 return 0;
61 }
62 if ( offset + len > h->file_size )
63 {
64 dprintf(warn, " offset+len > file size %llx, truncating\n",
65 h->file_size);
66 len = h->file_size - offset;
67 }
68
69 /* Try to find the offset in our range */
70 dprintf(warn, " Trying last, %d\n", last);
71 if ( h->map[h->last].buffer
72 && (offset & MREAD_BUF_MASK) == h->map[h->last].start_offset )
73 {
74 bind=h->last;
75 goto copy;
76 }
77
78 /* Scan to see if it's anywhere else */
79 dprintf(warn, " Scanning\n");
80 for(bind=0; bind<MREAD_MAPS; bind++)
81 if ( h->map[bind].buffer
82 && (offset & MREAD_BUF_MASK) == h->map[bind].start_offset )
83 {
84 dprintf(warn, " Found, index %d\n", bind);
85 break;
86 }
87
88 /* If we didn't find it, evict someone and map it */
89 if ( bind == MREAD_MAPS )
90 {
91 dprintf(warn, " Clock\n");
92 while(1)
93 {
94 h->clock++;
95 if(h->clock >= MREAD_MAPS)
96 h->clock=0;
97 dprintf(warn, " %d\n", h->clock);
98 if(h->map[h->clock].buffer == NULL)
99 {
100 dprintf(warn, " Buffer null, using\n");
101 break;
102 }
103 if(!h->map[h->clock].accessed)
104 {
105 dprintf(warn, " Not accessed, using\n");
106 break;
107 }
108 h->map[h->clock].accessed=0;
109 }
110 if(h->map[h->clock].buffer)
111 {
112 dprintf(warn, " Unmapping\n");
113 munmap(h->map[h->clock].buffer, MREAD_BUF_SIZE);
114 }
115 /* FIXME: Try MAP_HUGETLB? */
116 /* FIXME: Make sure this works on large files... */
117 h->map[h->clock].start_offset = offset & MREAD_BUF_MASK;
118 dprintf(warn, " Mapping %llx from offset %llx\n",
119 MREAD_BUF_SIZE, h->map[h->clock].start_offset);
120 h->map[h->clock].buffer = mmap(NULL, MREAD_BUF_SIZE, PROT_READ,
121 MAP_SHARED,
122 h->fd,
123 h->map[h->clock].start_offset);
124 dprintf(warn, " mmap returned %p\n", h->map[h->clock].buffer);
125 if ( h->map[h->clock].buffer == MAP_FAILED )
126 {
127 h->map[h->clock].buffer = NULL;
128 perror("mmap");
129 exit(1);
130 }
131 bind = h->clock;
132 }
133
134 h->last=bind;
135 copy:
136 h->map[bind].accessed=1;
137 b=h->map[bind].buffer;
138 boffset=offset - h->map[bind].start_offset;
139 if ( boffset + len > MREAD_BUF_SIZE )
140 bsize = MREAD_BUF_SIZE - boffset;
141 else
142 bsize = len;
143 dprintf(warn, " Using index %d, buffer at %p, buffer offset %llx len %d\n",
144 bind, b, boffset, bsize);
145
146 bcopy(b+boffset, rec, bsize);
147
148 /* Handle the boundary case; make sure this is after doing anything
149 * with the static variables*/
150 if ( len > bsize )
151 {
152 dprintf(warn, " Finishing up by reading l %d o %llx\n",
153 len-bsize, offset+bsize);
154 mread64(h, rec+bsize, len-bsize, offset+bsize);
155 }
156
157 /* FIXME: ?? */
158 return len;
159 #undef dprintf
160 }
161