1 static char rcsid[] = "$Id: access.c 222390 2020-04-10 12:44:01Z twu $";
2 #ifdef HAVE_CONFIG_H
3 #include <config.h>
4 #endif
5 
6 #include "access.h"
7 #include "list.h"
8 #include "intlist.h"
9 
10 #include <stdio.h>
11 #include <stddef.h>
12 #include <stdlib.h>
13 #include <string.h>		/* For strerror */
14 #include <errno.h>
15 #include <sys/stat.h>		/* For fstat */
16 
17 /* <unistd.h> and <sys/types.h> included in access.h */
18 #include <sys/mman.h>		/* For mmap */
19 
20 #define PROJECT_ID 42
21 #include <sys/ipc.h>
22 #include <sys/shm.h>		/* For shmat and shmdt */
23 #include "semaphore.h"
24 
25 
26 #ifdef USE_MPI
27 #include <mpi.h>
28 #endif
29 
30 #ifdef HAVE_FCNTL_H
31 #include <fcntl.h>		/* For open */
32 #endif
33 #ifdef HAVE_SYS_STAT_H
34 #include <sys/stat.h>		/* For open and fstat */
35 #endif
36 
37 #ifdef PAGESIZE_VIA_SYSCONF
38 #include <unistd.h>
39 #endif
40 #ifdef PAGESIZE_VIA_SYSCTL
41 #include <sys/sysctl.h>
42 #endif
43 
44 #include "assert.h"
45 #include "mem.h"
46 #include "types.h"
47 #include "fopen.h"
48 #include "stopwatch.h"
49 
50 #ifdef WORDS_BIGENDIAN
51 #include "bigendian.h"
52 #else
53 #include "littleendian.h"
54 #endif
55 
56 
57 #define MAX_KILL_ATTEMPTS 5	/* Limits on attempts to kill unattached memory segments */
58 
59 
60 #ifdef DEBUG
61 #define debug(x) x
62 #else
63 #define debug(x)
64 #endif
65 
66 static bool preload_shared_memory_p = false;
67 static bool unload_shared_memory_p = false;
68 
69 void
Access_setup(bool preload_shared_memory_p_in,bool unload_shared_memory_p_in)70 Access_setup (bool preload_shared_memory_p_in, bool unload_shared_memory_p_in) {
71   preload_shared_memory_p = preload_shared_memory_p_in;
72   unload_shared_memory_p = unload_shared_memory_p_in;
73   return;
74 }
75 
76 
77 
78 bool
Access_file_exists_p(char * filename)79 Access_file_exists_p (char *filename) {
80 #ifdef HAVE_STRUCT_STAT64
81   /* struct stat64 is now deprecated */
82   struct stat sb;
83 #else
84   struct stat sb;
85 #endif
86 
87 #ifdef HAVE_STAT64
88   /* stat64 is now deprecated */
89   if (stat(filename,&sb) == 0) {
90     return true;
91   } else {
92     return false;
93   }
94 #else
95   if (stat(filename,&sb) == 0) {
96     return true;
97   } else {
98     return false;
99   }
100 #endif
101 }
102 
103 
104 size_t
Access_filesize(char * filename)105 Access_filesize (char *filename) {
106 #ifdef HAVE_STRUCT_STAT64
107   /* struct stat64 is now deprecated */
108   struct stat sb;
109 #else
110   struct stat sb;
111 #endif
112 
113 #ifdef HAVE_STAT64
114   /* stat64 is now deprecated */
115   stat(filename,&sb);
116 #else
117   stat(filename,&sb);
118 #endif
119   debug(printf("filesize is %zu\n",(size_t) sb.st_size));
120   return (size_t) sb.st_size;
121 }
122 
123 
124 size_t
Access_file_copy(char * dest_file,char * source_file)125 Access_file_copy (char *dest_file, char *source_file) {
126   size_t nbytes = 0;
127   FILE *dest, *source;
128   int c;
129 
130   if ((source = FOPEN_READ_BINARY(source_file)) == NULL) {
131     fprintf(stderr,"Cannot open source file %s\n",source_file);
132     return 0;
133 
134   } else if ((dest = FOPEN_WRITE_BINARY(dest_file)) == NULL) {
135     fprintf(stderr,"Cannot open destination file %s\n",dest_file);
136     fclose(source);
137     return 0;
138 
139   } else {
140     while ((c = fgetc(source)) != EOF) {
141       fputc(c,dest);
142       nbytes++;
143     }
144     fclose(dest);
145     fclose(source);
146     return nbytes;
147   }
148 }
149 
150 
151 bool
Access_file_equal(char * file1,char * file2)152 Access_file_equal (char *file1, char *file2) {
153   FILE *fp1, *fp2;
154   int c1, c2;
155 
156   if ((fp1 = FOPEN_READ_BINARY(file1)) == NULL) {
157     fprintf(stderr,"Cannot open file %s\n",file1);
158     exit(9);
159 
160   } else if ((fp2 = FOPEN_READ_BINARY(file2)) == NULL) {
161     fprintf(stderr,"Cannot open file %s\n",file2);
162     fclose(fp1);
163     exit(9);
164 
165   } else {
166     c1 = fgetc(fp1);
167     c2 = fgetc(fp2);
168     while (c1 != EOF && c2 != EOF) {
169       if (c1 != c2) {
170 	fclose(fp2);
171 	fclose(fp1);
172 	return false;
173       }
174       c1 = fgetc(fp1);
175       c2 = fgetc(fp2);
176     }
177     fclose(fp2);
178     fclose(fp1);
179 
180     if (c1 == EOF && c2 == EOF) {
181       return true;
182     } else {
183       return false;
184     }
185   }
186 }
187 
188 
189 int
Access_fileio(char * filename)190 Access_fileio (char *filename) {
191   int fd;
192 
193   if ((fd = open(filename,O_RDONLY,0764)) < 0) {
194     fprintf(stderr,"Error: can't open file %s with open for reading\n",filename);
195     exit(9);
196   }
197   return fd;
198 }
199 
200 int
Access_fileio_rw(char * filename)201 Access_fileio_rw (char *filename) {
202   int fd;
203 
204   if ((fd = open(filename,O_RDWR | O_CREAT | O_TRUNC,0764)) < 0) {
205     fprintf(stderr,"Error: can't open file %s with open for reading/writing\n",filename);
206     exit(9);
207   }
208   return fd;
209 }
210 
211 
212 #if 0
213 #ifndef WORDS_BIGENDIAN
214 /* Previously needed as a test on Macintosh machines */
215 static unsigned char
216 first_nonzero_char (size_t *i, char *filename) {
217   size_t len;
218   FILE *fp;
219   unsigned char value = 0;
220   void *p;
221 
222   len = Access_filesize(filename);
223 
224   if ((fp = FOPEN_READ_BINARY(filename)) == NULL) {
225     fprintf(stderr,"Error: can't open file %s with fopen\n",filename);
226     exit(9);
227   } else {
228     *i = 0;
229     p = (void *) &value;
230     while ((size_t) *i < len && fread(p,sizeof(unsigned char),1,fp) > 0 &&
231 	   value == 0) {
232       *i += 1;
233     }
234     if (value == 0) {
235       *i = -1;
236     }
237     fclose(fp);
238     return value;
239   }
240 }
241 
242 static UINT4
243 first_nonzero_uint (size_t *i, char *filename) {
244   size_t len;
245   FILE *fp;
246   UINT4 value = 0;
247   void *p;
248 
249   len = Access_filesize(filename);
250 
251   if ((fp = FOPEN_READ_BINARY(filename)) == NULL) {
252     fprintf(stderr,"Error: can't open file %s with fopen\n",filename);
253     exit(9);
254   } else {
255     *i = 0;
256     p = (void *) &value;
257     while ((size_t) *i < len && fread(p,sizeof(UINT4),1,fp) > 0 &&
258 	   value == 0) {
259       *i += 1;
260     }
261     if (value == 0) {
262       *i = -1;
263     }
264     fclose(fp);
265     return value;
266   }
267 }
268 
269 static UINT8
270 first_nonzero_uint8 (size_t *i, char *filename) {
271   size_t len;
272   FILE *fp;
273   UINT8 value = 0;
274   void *p;
275 
276   len = Access_filesize(filename);
277   if ((fp = FOPEN_READ_BINARY(filename)) == NULL) {
278     fprintf(stderr,"Error: can't open file %s with fopen\n",filename);
279     exit(9);
280   } else {
281     *i = 0;
282     p = (void *) &value;
283     while ((size_t) *i < len && fread(p,sizeof(UINT8),1,fp) > 0 &&
284 	   value == 0) {
285       *i += 1;
286     }
287     if (value == 0) {
288       *i = -1;
289     }
290     fclose(fp);
291     return value;
292   }
293 }
294 #endif
295 #endif
296 
297 
298 /************************************************************************
299  *   Functions for shared memory and semaphores
300  ************************************************************************/
301 
302 static List_T shmem_memory = NULL;
303 static Intlist_T shmem_ids = NULL;
304 static Intlist_T semaphore_ids = NULL;
305 
306 
307 #if 0
308 /* See if item is already in shared memory */
309 static bool
310 shmem_exists_p (int *shmid, key_t key) {
311   if ((*shmid = shmget(key,0,0)) == -1) {
312     return false;
313   } else {
314     return true;
315   }
316 }
317 #endif
318 
319 
320 static short
shmem_nattached(int shmid)321 shmem_nattached (int shmid) {
322   struct shmid_ds buf;
323 
324   if (shmctl(shmid,IPC_STAT,&buf) == -1) {
325 #if 0
326     fprintf(stderr,"Error in shmem_nattached with shmctl.  Error %d: %s\n",
327 	    errno,strerror(errno));
328 #endif
329     return -1;
330   } else {
331     return buf.shm_nattch;
332   }
333 }
334 
335 
336 #if 0
337 void
338 Access_shmem_remove (char *filename) {
339   key_t key;
340   int shmid, semid;
341   struct shmid_ds *buf = NULL;
342 
343   key = ftok(filename,PROJECT_ID);
344   if (shmem_exists_p(&shmid,key) == false) {
345     /* Nothing to do */
346   } else if (shmctl(shmid,IPC_RMID,buf) == -1) {
347     fprintf(stderr,"Error with shmctl.  Error %d: %s\n",errno,strerror(errno));
348   } else {
349     fprintf(stderr,"Successfully removed existing memory\n");
350   }
351 
352   if ((semid = semget(key,/*nsems*/0,0)) == -1) {
353     /* Nothing to do */
354   } else {
355     fprintf(stderr,"Removing semaphore set %d\n",semid);
356     semctl(semid,SEMNO_NA,IPC_RMID,NULL);
357   }
358 
359   return;
360 }
361 #endif
362 
363 void
Access_controlled_cleanup()364 Access_controlled_cleanup () {
365   List_free(&shmem_memory);
366   Intlist_free(&shmem_ids);
367   Intlist_free(&semaphore_ids);
368   return;
369 }
370 
371 
372 void
Access_emergency_cleanup()373 Access_emergency_cleanup () {
374   List_T p;
375   Intlist_T r, q;
376   void *memory;
377   int shmid, semid;
378   int nattached;
379   struct shmid_ds *buf = NULL;
380 
381   fprintf(stderr,"Calling Access_emergency_cleanup\n");
382 
383   /* First, detach all memory */
384   for (p = shmem_memory; p != NULL; p = List_next(p)) {
385     memory = List_head(p);
386     if (shmdt(memory) == -1) {
387 #if 0
388       /* Somehow, shmdt forks and prints the error message and continues with the rest of the code */
389       fprintf(stderr,"Error in Access_emergency_cleanup with shmdt on memory %p, shmid %d.  Error %d: %s\n",
390 	      memory,shmid,errno,strerror(errno));
391 #endif
392     }
393   }
394 
395   if (unload_shared_memory_p == true) {
396     /* Don't try to fix */
397 
398   } else if (preload_shared_memory_p == true) {
399     /* Don't try to fix */
400 
401   } else {
402     /* Delete memory and semaphores */
403     for (r = semaphore_ids, q = shmem_ids; r != NULL; r = Intlist_next(r), q = Intlist_next(q)) {
404       semid = Intlist_head(r);
405       shmid = Intlist_head(q);
406 
407       if (Semaphore_get_value(semid,SEMNO_KEEP) == SEMAPHORE_RESIDENT) {
408 	/* Keep memory resident */
409       } else if ((nattached = shmem_nattached(shmid)) > 0) {
410 	/* Keep memory resident */
411       } else if (shmctl(shmid,IPC_RMID,buf) == -1) {
412 	/* Error in deleting memory, possibly with multiple threads trying to delete */
413 	/* fprintf(stderr,"Error in Access_emergency_cleanup with shmctl.  Error %d: %s\n",
414 	   errno,strerror(errno)); */
415 	/* Semaphore_delete(semid); */
416       } else {
417 	fprintf(stderr,"Removed existing memory for shmid %d\n",shmid);
418 	Semaphore_delete(semid);
419       }
420     }
421   }
422 
423   if (shmem_memory != NULL) {
424     fprintf(stderr,"\n");
425     fprintf(stderr,"You may want to run 'ipcs -m' to see if any shared memory segments are still in use\n");
426     fprintf(stderr,"You can remove a shared memory segment manually by doing 'ipcrm -m <shmid>'\n");
427     fprintf(stderr,"\n");
428   }
429 
430   List_free(&shmem_memory);
431   Intlist_free(&shmem_ids);
432   Intlist_free(&semaphore_ids);
433 
434   return;
435 }
436 
437 
438 void
Access_deallocate(void * memory,int shmid,key_t key)439 Access_deallocate (void *memory, int shmid, key_t key) {
440   struct shmid_ds *buf = NULL;
441   short nattached;
442   int semid;
443 
444   /* First, detach memory */
445   if (shmdt(memory) == -1) {
446 #if 0
447     /* Somehow, shmdt forks and prints the error message and continues with the rest of the code */
448     fprintf(stderr,"Error in Access_emergency_cleanup with shmdt on memory %p, shmid %d.  Error %d: %s\n",
449 	    memory,shmid,errno,strerror(errno));
450 #endif
451   }
452 
453   /* Then, delete memory and semaphores, if applicable */
454   if ((semid = Semaphore_find(key)) != -1 && Semaphore_get_value(semid,SEMNO_KEEP) == SEMAPHORE_RESIDENT) {
455     fprintf(stderr,"Keeping memory for shmid %d resident, because it was pre-loaded.  To remove, run gsnap on this genome index with --unload-shared-memory\n",
456 	    shmid);
457 
458   } else if ((nattached = shmem_nattached(shmid)) > 0) {
459     fprintf(stderr,"Keeping memory for shmid %d resident, because it is being used by %d processes\n",
460 	    shmid,nattached);
461 
462   } else if (shmctl(shmid,IPC_RMID,buf) == -1) {
463     /* Somehow, shmctl forks and prints the error message and continues with the rest of the code */
464     /* fprintf(stderr,"Error in Access_deallocate with shmctl.  Error %d: %s\n",errno,strerror(errno)); */
465     /* Semaphore_delete(semid); */
466 
467   } else {
468     fprintf(stderr,"Removed existing memory for shmid %d\n",shmid);
469     Semaphore_delete(semid);
470   }
471 
472   return;
473 }
474 
475 
476 /* Same as Access_deallocate, but without deleting semaphore */
477 void
Access_deallocate_wo_semaphore(void * memory,int shmid,key_t key)478 Access_deallocate_wo_semaphore (void *memory, int shmid, key_t key) {
479   struct shmid_ds *buf = NULL;
480   short nattached;
481   int semid;
482 
483   /* First, detach memory */
484   if (shmdt(memory) == -1) {
485 #if 0
486     /* Somehow, shmdt forks and prints the error message and continues with the rest of the code */
487     fprintf(stderr,"Error in Access_emergency_cleanup with shmdt on memory %p, shmid %d.  Error %d: %s\n",
488 	    memory,shmid,errno,strerror(errno));
489 #endif
490   }
491 
492   /* Then, delete memory and semaphores, if applicable */
493   if ((semid = Semaphore_find(key)) != -1 && Semaphore_get_value(semid,SEMNO_KEEP) == SEMAPHORE_RESIDENT) {
494     fprintf(stderr,"Keeping memory for shmid %d resident, because it was pre-loaded.  To remove, run gsnap on this genome index with --unload-shared-memory\n",
495 	    shmid);
496 
497   } else if ((nattached = shmem_nattached(shmid)) > 0) {
498     fprintf(stderr,"Keeping memory for shmid %d resident, because it is being used by %d processes\n",
499 	    shmid,nattached);
500 
501   } else if (shmctl(shmid,IPC_RMID,buf) == -1) {
502     /* Somehow, shmctl forks and prints the error message and continues with the rest of the code */
503     /* fprintf(stderr,"Error in Access_deallocate with shmctl.  Error %d: %s\n",errno,strerror(errno)); */
504     /* Semaphore_delete(semid); */
505 
506   } else {
507     fprintf(stderr,"Removed existing memory for shmid %d\n",shmid);
508     /* Semaphore_delete(semid); */
509   }
510 
511   return;
512 }
513 
514 
515 
516 #define FREAD_BATCH 100000000	/* 100 million elements at a time */
517 
518 static void
copy_memory_from_file(void * memory,char * filename,size_t filesize,size_t eltsize)519 copy_memory_from_file (void *memory, char *filename, size_t filesize, size_t eltsize) {
520   FILE *fp;
521   void *p;
522   size_t i;
523 
524   if ((fp = FOPEN_READ_BINARY(filename)) == NULL) {
525     fprintf(stderr,"Error: can't open file %s with fopen\n",filename);
526     exit(9);
527   }
528 
529   if (eltsize == 1) {
530     for (i = 0; i + FREAD_BATCH < filesize/eltsize; i += FREAD_BATCH) {
531       p = (void *) &(((unsigned char *) memory)[i]);
532       fread(p,sizeof(unsigned char),FREAD_BATCH,fp);
533     }
534 
535     if (i < filesize/eltsize) {
536       p = (void *) &(((unsigned char *) memory)[i]);
537       fread(p,sizeof(unsigned char),filesize/eltsize - i,fp);
538     }
539 
540   } else if (eltsize == 2) {
541     for (i = 0; i + FREAD_BATCH < filesize/eltsize; i += FREAD_BATCH) {
542       p = (void *) &(((UINT2 *) memory)[i]);
543       fread(p,sizeof(UINT2),FREAD_BATCH,fp);
544     }
545 
546     if (i < filesize/eltsize) {
547       p = (void *) &(((UINT2 *) memory)[i]);
548       fread(p,sizeof(UINT2),filesize/eltsize - i,fp);
549     }
550 
551   } else if (eltsize == 4) {
552     for (i = 0; i + FREAD_BATCH < filesize/eltsize; i += FREAD_BATCH) {
553       p = (void *) &(((UINT4 *) memory)[i]);
554       fread(p,sizeof(UINT4),FREAD_BATCH,fp);
555     }
556 
557     if (i < filesize/eltsize) {
558       p = (void *) &(((UINT4 *) memory)[i]);
559       fread(p,sizeof(UINT4),filesize/eltsize - i,fp);
560     }
561 
562   } else if (eltsize == 8) {
563     for (i = 0; i + FREAD_BATCH < filesize/eltsize; i += FREAD_BATCH) {
564       p = (void *) &(((UINT8 *) memory)[i]);
565       fread(p,sizeof(UINT8),FREAD_BATCH,fp);
566     }
567 
568     if (i < filesize/eltsize) {
569       p = (void *) &(((UINT8 *) memory)[i]);
570       fread(p,sizeof(UINT8),filesize/eltsize - i,fp);
571     }
572 
573   } else {
574     fprintf(stderr,"Access_allocated called with an element size of %d, which is not handled\n",(int) eltsize);
575     exit(9);
576   }
577   fclose(fp);
578 
579   return;
580 }
581 
582 
583 static void
copy_limited_from_file(void * memory,char * filename,size_t filesize,size_t eltsize)584 copy_limited_from_file (void *memory, char *filename, size_t filesize, size_t eltsize) {
585   FILE *fp;
586   void *p;
587 
588   if ((fp = FOPEN_READ_BINARY(filename)) == NULL) {
589     fprintf(stderr,"Error: can't open file %s with fopen\n",filename);
590     exit(9);
591   }
592 
593   if (eltsize == 1) {
594     p = (void *) &(((unsigned char *) memory)[0]);
595     if (FREAD_BATCH < filesize/eltsize) {
596       fread(p,sizeof(unsigned char),FREAD_BATCH,fp);
597     } else {
598       fread(p,sizeof(unsigned char),filesize/eltsize,fp);
599     }
600 
601   } else if (eltsize == 2) {
602     p = (void *) &(((UINT2 *) memory)[0]);
603     if (FREAD_BATCH < filesize/eltsize) {
604       fread(p,sizeof(UINT2),FREAD_BATCH,fp);
605     } else {
606       fread(p,sizeof(UINT2),filesize/eltsize,fp);
607     }
608 
609   } else if (eltsize == 4) {
610     p = (void *) &(((UINT4 *) memory)[0]);
611     if (FREAD_BATCH < filesize/eltsize) {
612       fread(p,sizeof(UINT4),FREAD_BATCH,fp);
613     } else {
614       fread(p,sizeof(UINT4),filesize/eltsize,fp);
615     }
616 
617   } else if (eltsize == 8) {
618     p = (void *) &(((UINT8 *) memory)[0]);
619     if (FREAD_BATCH < filesize/eltsize) {
620       fread(p,sizeof(UINT8),FREAD_BATCH,fp);
621     } else {
622       fread(p,sizeof(UINT8),filesize/eltsize,fp);
623     }
624 
625   } else {
626     fprintf(stderr,"Access_allocated called with an element size of %d, which is not handled\n",(int) eltsize);
627     exit(9);
628   }
629   fclose(fp);
630 
631   return;
632 }
633 
634 
635 static void *
shmem_attach(int * shmid,key_t * key,char * filename,size_t filesize,size_t eltsize)636 shmem_attach (int *shmid, key_t *key, char *filename, size_t filesize, size_t eltsize) {
637   void *memory = NULL;
638   int semid = -1;
639   ushort values[NSEMAPHORES];
640   int nattached;
641   bool donep;
642   int niter;
643 
644   values[SEMNO_LOCK] = -1;
645   /* For some reason, these values are not being set, so using Semaphore_set_value below */
646   if (preload_shared_memory_p == true) {
647     values[SEMNO_KEEP] = SEMAPHORE_RESIDENT;
648   } else {
649     values[SEMNO_KEEP] = SEMAPHORE_FREEABLE;
650   }
651 
652   *key = ftok(filename,PROJECT_ID);
653   while (semid == -1) {
654     if ((semid = Semaphore_create(*key,/*nsems*/NSEMAPHORES,values)) != -1) {
655       /* Created a new semaphore */
656       if (preload_shared_memory_p == true) {
657 	Semaphore_set_value(semid,SEMNO_KEEP,SEMAPHORE_RESIDENT);
658       }
659 
660     } else if ((semid = Semaphore_find(*key)) != -1) {
661       /* Got existing semaphore */
662       if (unload_shared_memory_p == true) {
663 	Semaphore_set_value(semid,SEMNO_KEEP,SEMAPHORE_FREEABLE);
664       }
665 
666 #if 0
667       if (Semaphore_get_value(semid,SEMNO_KEEP) == SEMNO_RESIDENT) {
668 	/* Semaphore exists only to keep memory resident */
669 	fprintf(stderr,"Using shared memory already resident in system\n");
670 
671       } else {
672 	/* Semaphore being created */
673 	semaphore_wait_for_creation(semid);
674       }
675 #endif
676     }
677   }
678 
679   /* The process that created the semaphore will proceed, while the
680      others wait.  They will be woken up when the semaphore is
681      removed. */
682 
683   donep = false;
684   niter = 0;
685   while (donep == false) {
686     if ((*shmid = shmget(*key,filesize,IPC_CREAT | IPC_EXCL |
687 #ifdef HAVE_SHM_NORESERVE
688 			 SHM_NORESERVE |
689 #endif
690 			 0666)) != -1) {
691       /* Created new shared memory */
692       if ((memory = shmat(*shmid,NULL,0)) == (void *) -1) {
693 	fprintf(stderr,"Error with shmat (1).  Error %d: %s\n",errno,strerror(errno));
694 	exit(9);
695 
696       } else if (unload_shared_memory_p == true) {
697 	semaphore_ids = Intlist_push(semaphore_ids,semid);
698 	shmem_memory = List_push(shmem_memory,memory);
699 	shmem_ids = Intlist_push(shmem_ids,*shmid);
700 	copy_limited_from_file(memory,filename,filesize,eltsize);
701 	donep = true;
702 
703       } else {
704 	semaphore_ids = Intlist_push(semaphore_ids,semid);
705 	shmem_memory = List_push(shmem_memory,memory);
706 	shmem_ids = Intlist_push(shmem_ids,*shmid);
707 	copy_memory_from_file(memory,filename,filesize,eltsize);
708 	fprintf(stderr,"Attached new memory for %s...",filename);
709 	donep = true;
710       }
711 
712     } else if ((*shmid = shmget(*key,0,0)) != -1) {
713       /* Found existing shared memory */
714       if ((memory = shmat(*shmid,NULL,0)) == (void *) -1) {
715 	fprintf(stderr,"Error with shmat (2).  Error %d: %s\n",errno,strerror(errno));
716 	exit(9);
717 
718       } else if ((nattached = shmem_nattached(*shmid)) > 1) {
719 	/* Existing memory is indeed valid: attached (by a process other than this one) */
720 	semaphore_ids = Intlist_push(semaphore_ids,semid);
721 	shmem_memory = List_push(shmem_memory,memory);
722 	shmem_ids = Intlist_push(shmem_ids,*shmid);
723 	fprintf(stderr,"Attached existing memory (%d attached) for %s...",nattached,filename);
724 	donep = true;
725 
726       } else if (niter > MAX_KILL_ATTEMPTS) {
727 	/* Existing memory is not attached by any other process, but unable to kill.  Could be corrupted */
728 	fprintf(stderr,"Abandoned shared memory found, but could not be removed after %d attempts.  Using malloc instead of shared memory\n",niter);
729 	memory = (void *) NULL;
730 	donep = true;
731 
732       } else {
733 	/* Existing memory is not attached by any other process.  Could be corrupted. */
734 	fprintf(stderr,"Clearing existing shared memory for %s...\n",filename);
735 	Access_deallocate_wo_semaphore(memory,*shmid,*key);
736 
737 	/* Now loop above to try again */
738       }
739 
740     } else {
741       fprintf(stderr,"Using malloc instead of shmget for file %s\n",filename);
742       memory = (void *) NULL;
743       donep = true;
744     }
745 
746     niter++;
747   }
748 
749 #if 0
750   /* The process that proceeded removes the semaphore here, allowing
751      the other processes to continue after their waits.  The other
752      processes will try to remove the semaphore too, yielding an
753      error, which we simply ignore. */
754   if (unload_shared_memory_p == true) {
755     /* Deleting semaphore will allow Access_deallocate to remove the shared memory */
756     Semaphore_delete(semid);
757 
758   } else if (Semaphore_get_value(semid,SEMNO_KEEP) == SEMAPHORE_RESIDENT) {
759     /* Exists to keep memory resident */
760     fprintf(stderr,"Semaphore %d intended to keep memory resident\n",semid);
761 
762   } else if (preload_shared_memory_p == false) {
763     Semaphore_delete(semid);
764 
765   } else {
766     /* Keep semaphore in system, but indicate we are done with creation */
767     /* fprintf(stderr,"Forcing memory for %d to stay resident in system\n",*shmid); */
768 #if 0
769     semaphore_set_value(semid,SEMAPHORE_KEEP_RESIDENT,/*value*/0);
770 #endif
771   }
772 #endif
773 
774 
775   return memory;
776 }
777 
778 
779 /* Bigendian conversion not needed after this */
780 void *
Access_allocate_private(Access_T * access,size_t * len,double * seconds,char * filename,size_t eltsize)781 Access_allocate_private (Access_T *access, size_t *len, double *seconds, char *filename, size_t eltsize) {
782   void *memory;
783 #ifdef CHECK
784   void *memory2;
785 #endif
786 #if 0 && defined (USE_MPI)
787   /* Does not work.  Gets ftruncate error */
788   MPI_Comm comm;
789   MPI_Win win;
790 #endif
791   Stopwatch_T stopwatch;
792 
793   assert(filename != NULL);
794 
795   *len = Access_filesize(filename);
796   if (*len == 0) {
797     *seconds = 0.0;
798     return (void *) NULL;
799   }
800 
801   Stopwatch_start(stopwatch = Stopwatch_new());
802 
803 #ifdef CHECK
804   memory2 = (void *) MALLOC(*len);
805   if ((fp = FOPEN_READ_BINARY(filename)) == NULL) {
806     fprintf(stderr,"Error: can't open file %s with fopen\n",filename);
807     exit(9);
808   }
809 
810   if (eltsize == 1) {
811     FREAD_CHARS(memory2,(*len)/eltsize,fp);
812   } else if (eltsize == 2) {
813     FREAD_USHORTS(memory2,(*len)/eltsize,fp);
814   } else if (eltsize == 4) {
815     FREAD_UINTS(memory2,(*len)/eltsize,fp);
816   } else if (eltsize == 8) {
817     FREAD_UINT8S(memory2,(*len)/eltsize,fp);
818   } else {
819     fprintf(stderr,"Access_allocated called with an element size of %d, which is not handled\n",(int) eltsize);
820     exit(9);
821   }
822   fclose(fp);
823 #endif
824 
825   memory = (void *) MALLOC(*len);
826   copy_memory_from_file(memory,filename,/*filesize*/*len,eltsize);
827   *access = ALLOCATED_PRIVATE;
828 
829   /* Note: the following (old non-batch mode) requires conversion to bigendian later, as needed */
830   /* fread(new->offsets,eltsize,sb.st_size/eltsize,fp); */
831 
832 #ifdef CHECK
833   for (i = 0; i < *len; i++) {
834     if (((unsigned char *) memory)[i] != ((unsigned char *) memory2)[i]) {
835       abort();
836     }
837   }
838   FREE(memory2);
839 #endif
840 
841   *seconds = Stopwatch_stop(stopwatch);
842   Stopwatch_free(&stopwatch);
843 
844   return memory;
845 }
846 
847 
848 /* Bigendian conversion not needed after this */
849 void *
Access_allocate_shared(Access_T * access,int * shmid,key_t * key,int * fd,size_t * len,double * seconds,char * filename,size_t eltsize)850 Access_allocate_shared (Access_T *access, int *shmid, key_t *key, int *fd, size_t *len, double *seconds, char *filename, size_t eltsize) {
851   void *memory;
852 #ifdef CHECK
853   void *memory2;
854 #endif
855 #if 0 && defined (USE_MPI)
856   /* Does not work.  Gets ftruncate error */
857   MPI_Comm comm;
858   MPI_Win win;
859 #endif
860   Stopwatch_T stopwatch;
861 
862   assert(filename != NULL);
863 
864   *len = (size_t) Access_filesize(filename);
865   if (*len == 0) {
866     *seconds = 0.0;
867     return (void *) NULL;
868   }
869 
870   Stopwatch_start(stopwatch = Stopwatch_new());
871 
872 #ifdef CHECK
873   memory2 = (void *) MALLOC(*len);
874   if ((fp = FOPEN_READ_BINARY(filename)) == NULL) {
875     fprintf(stderr,"Error: can't open file %s with fopen\n",filename);
876     exit(9);
877   }
878 
879   if (eltsize == 1) {
880     FREAD_CHARS(memory2,(*len)/eltsize,fp);
881   } else if (eltsize == 2) {
882     FREAD_USHORTS(memory2,(*len)/eltsize,fp);
883   } else if (eltsize == 4) {
884     FREAD_UINTS(memory2,(*len)/eltsize,fp);
885   } else if (eltsize == 8) {
886     FREAD_UINT8S(memory2,(*len)/eltsize,fp);
887   } else {
888     fprintf(stderr,"Access_allocated called with an element size of %d, which is not handled\n",(int) eltsize);
889     exit(9);
890   }
891   fclose(fp);
892 #endif
893 
894 #if 0 && defined(USE_MPI)
895   /* Does not work.  Gives ftruncate error */
896   MPI_Comm_split_type(MPI_COMM_WORLD,MPI_COMM_TYPE_SHARED,0,MPI_INFO_NULL,&comm);
897   MPI_Win_allocate_shared(*len,/*disp_unit*/1,MPI_INFO_NULL,comm,&memory,&win);
898   MPI_Win_free(&win);
899 #elif defined(HAVE_MMAP)
900   if ((memory = shmem_attach(&(*shmid),&(*key),filename,/*filesize*/*len,eltsize)) != NULL) {
901     *access = ALLOCATED_SHARED;
902   } else {
903     fprintf(stderr,"shm_attach not working on file %s, so using memory mapping instead on %lu bytes\n",
904 	    filename,*len);
905     *shmid = 0;
906     memory = Access_mmap(&(*fd),&(*len),&(*seconds),filename,/*randomp*/true);
907 #if 0
908     /* Crashes because memory is read-only */
909     copy_memory_from_file(memory,filename,/*filesize*/*len,eltsize);
910 #endif
911     *access = MMAPPED;
912   }
913 #else
914   if ((memory = shmem_attach(&(*shmid),&(*key),filename,/*filesize*/*len,eltsize)) != NULL) {
915     *access = ALLOCATED_SHARED;
916   } else {
917     fprintf(stderr,"shm_attach not working on file %s, so using malloc instead on %lu bytes\n",
918 	    filename,*len);
919     *shmid = 0;
920     memory = (void *) MALLOC(*len);
921     copy_memory_from_file(memory,filename,/*filesize*/*len,eltsize);
922     *access = ALLOCATED_PRIVATE;
923   }
924 #endif
925 
926   /* Note: the following (old non-batch mode) requires conversion to bigendian later, as needed */
927   /* fread(new->offsets,eltsize,sb.st_size/eltsize,fp); */
928 
929 #ifdef CHECK
930   for (i = 0; i < *len; i++) {
931     if (((unsigned char *) memory)[i] != ((unsigned char *) memory2)[i]) {
932       abort();
933     }
934   }
935   FREE(memory2);
936 #endif
937 
938   if (*access == MMAPPED) {
939     /* Already computed seconds */
940   } else {
941     *seconds = Stopwatch_stop(stopwatch);
942   }
943   Stopwatch_free(&stopwatch);
944 
945   return memory;
946 }
947 
948 
949 #define PAGESIZE 1024*4
950 
951 static int
get_pagesize()952 get_pagesize () {
953 
954 #ifdef PAGESIZE_VIA_SYSCTL
955   int pagesize;
956   size_t pagelen;
957   int mib[2];
958 #endif
959 
960 #ifdef __STRICT_ANSI__
961   return PAGESIZE;
962 #elif defined(HAVE_GETPAGESIZE)
963   return getpagesize();
964 #elif defined(PAGESIZE_VIA_SYSCONF)
965   return (int) sysconf(_SC_PAGESIZE);
966 #elif defined(PAGESIZE_VIA_SYSCTL)
967   pagelen = sizeof(pagesize);
968   mib[0] = CTL_HW;
969   mib[1] = HW_PAGESIZE;
970   sysctl(mib,2,&pagesize,&pagelen,NULL,0);
971   return pagesize;
972 #else
973   return PAGESIZE;
974 #endif
975 
976 }
977 
978 
979 #ifdef HAVE_MMAP
980 /* Returns NULL if mmap fails.  Bigendian conversion required */
981 #ifdef HAVE_CADDR_T
982 caddr_t
983 #else
984 void *
985 #endif
Access_mmap(int * fd,size_t * len,double * seconds,char * filename,bool randomp)986 Access_mmap (int *fd, size_t *len, double *seconds, char *filename, bool randomp) {
987   size_t length;
988 #ifdef HAVE_CADDR_T
989   caddr_t memory;
990 #else
991   void *memory;
992 #endif
993   Stopwatch_T stopwatch;
994 
995   Stopwatch_start(stopwatch = Stopwatch_new());
996 
997   if (filename == NULL) {
998     abort();
999 
1000   } else if ((*len = length = Access_filesize(filename)) == 0U) {
1001     fprintf(stderr,"Warning: file %s is empty\n",filename);
1002     *fd = open(filename,O_RDONLY,0764); /* Still need to initialize value */
1003     memory = (void *) NULL;
1004 
1005   } else if ((*fd = open(filename,O_RDONLY,0764)) < 0) {
1006     fprintf(stderr,"Error: can't open file %s with open for reading\n",filename);
1007     exit(9);
1008 
1009   } else if (sizeof(size_t) <= 4 && length > MAX32BIT) {
1010     debug(printf("Too big to mmap\n"));
1011     *len = 0;
1012     memory = (void *) NULL;
1013 
1014   } else {
1015     *len = length;
1016     memory = mmap(NULL,length,PROT_READ,0
1017 #ifdef HAVE_MMAP_MAP_PRIVATE
1018 		  |MAP_PRIVATE
1019 #endif
1020 #ifdef HAVE_MMAP_MAP_FILE
1021 		  |MAP_FILE
1022 #endif
1023 #ifdef HAVE_MMAP_MAP_VARIABLE
1024 		  |MAP_VARIABLE
1025 #endif
1026 		  /*|MAP_NORESERVE*/
1027 		  ,*fd,0);
1028 
1029     if (memory == MAP_FAILED) {
1030       fprintf(stderr,"Error in access.c (1): Got mmap failure on file %s with length %jd.  Error %d: %s\n",
1031 	      filename,length,errno,strerror(errno));
1032       debug(printf("Got MAP_FAILED on file %s with length %jd\n",filename,length));
1033       memory = (void *) NULL;
1034 
1035     } else if (randomp == true) {
1036       debug(printf("Got mmap of %jd bytes at %p to %p\n",length,memory,memory+length-1));
1037 #ifdef HAVE_MADVISE
1038 #ifdef HAVE_MADVISE_MADV_RANDOM
1039       madvise(memory,*len,MADV_RANDOM);
1040 #endif
1041 #endif
1042 
1043     } else {
1044       debug(printf("Got mmap of %jd bytes at %p to %p\n",length,memory,memory+length-1));
1045 #ifdef HAVE_MADVISE
1046 #ifdef HAVE_MADVISE_MADV_DONTNEED
1047       madvise(memory,*len,MADV_DONTNEED);
1048 #endif
1049 #endif
1050     }
1051   }
1052 
1053   *seconds = Stopwatch_stop(stopwatch);
1054   Stopwatch_free(&stopwatch);
1055 
1056   return memory;
1057 }
1058 #endif
1059 
1060 
1061 
1062 #ifdef HAVE_MMAP
1063 /* Returns NULL if mmap fails.  Bigendian conversion required */
1064 #ifdef HAVE_CADDR_T
1065 caddr_t
1066 #else
1067 void *
1068 #endif
Access_mmap_offset(int * remainder,int fd,size_t offset,size_t length,bool randomp)1069 Access_mmap_offset (int *remainder, int fd, size_t offset, size_t length, bool randomp) {
1070 #ifdef HAVE_CADDR_T
1071   caddr_t memory;
1072 #else
1073   void *memory;
1074 #endif
1075 
1076   if (length == 0) {
1077     abort();
1078   }
1079 
1080   *remainder = offset % get_pagesize();
1081   offset -= (size_t) *remainder;
1082   length += (size_t) *remainder;
1083 
1084   if (sizeof(size_t) <= 4 && length > MAX32BIT) {
1085     debug(printf("Too big to mmap\n"));
1086     memory = (void *) NULL;
1087   } else {
1088     memory = mmap(NULL,length,PROT_READ,0
1089 #ifdef HAVE_MMAP_MAP_PRIVATE
1090 		  |MAP_PRIVATE
1091 #endif
1092 #ifdef HAVE_MMAP_MAP_FILE
1093 		  |MAP_FILE
1094 #endif
1095 #ifdef HAVE_MMAP_MAP_VARIABLE
1096 		  |MAP_VARIABLE
1097 #endif
1098 		  /*|MAP_NORESERVE*/
1099 		  ,fd,offset);
1100 
1101     if (memory == MAP_FAILED) {
1102       fprintf(stderr,"Error in access.c (2): Got mmap failure on fd %d, offset %jd, length %jd.  Error %d: %s\n",
1103 	      fd,offset,length,errno,strerror(errno));
1104       debug(printf("Got MAP_FAILED on fd %d, offset %jd, length %zu\n",fd,offset,length));
1105       memory = (void *) NULL;
1106 
1107     } else if (randomp == true) {
1108       debug(printf("Got mmap of %jd bytes at %p to %p\n",length,memory,memory+length-1));
1109 #ifdef HAVE_MADVISE
1110 #ifdef HAVE_MADVISE_MADV_RANDOM
1111       madvise(memory,length,MADV_RANDOM);
1112 #endif
1113 #endif
1114 
1115     } else {
1116       debug(printf("Got mmap of %jd bytes at %p to %p\n",length,memory,memory+length-1));
1117 #ifdef HAVE_MADVISE
1118 #ifdef HAVE_MADVISE_MADV_DONTNEED
1119       madvise(memory,length,MADV_DONTNEED);
1120 #endif
1121 #endif
1122     }
1123   }
1124 
1125   return memory;
1126 }
1127 #endif
1128 
1129 
1130 #if 0
1131 /* All programs are read-only */
1132 #ifdef HAVE_MMAP
1133 /* Returns NULL if mmap fails.  Bigendian conversion required */
1134 #ifdef HAVE_CADDR_T
1135 caddr_t
1136 #else
1137 void *
1138 #endif
1139 Access_mmap_rw (int *fd, size_t *len, char *filename, bool randomp) {
1140   size_t length;
1141 #ifdef HAVE_CADDR_T
1142   caddr_t memory;
1143 #else
1144   void *memory;
1145 #endif
1146 
1147   if ((*len = length = Access_filesize(filename)) == 0U) {
1148     fprintf(stderr,"Warning: file %s is empty\n",filename);
1149     *fd = open(filename,O_RDWR,0764); /* Still need to initialize value */
1150     memory = (void *) NULL;
1151   } else if ((*fd = open(filename,O_RDWR,0764)) < 0) {
1152     fprintf(stderr,"Error: can't open file %s with open for reading/writing\n",filename);
1153     exit(9);
1154   } else if (sizeof(size_t) <= 4 && length > MAX32BIT) {
1155     debug(printf("Too big to mmap\n"));
1156     *len = 0;
1157     memory = (void *) NULL;
1158   } else {
1159     *len = length;
1160     memory = mmap(NULL,length,PROT_READ|PROT_WRITE,0
1161 #ifdef HAVE_MMAP_MAP_SHARED
1162 		  |MAP_SHARED
1163 #endif
1164 #ifdef HAVE_MMAP_MAP_FILE
1165 		  |MAP_FILE
1166 #endif
1167 #ifdef HAVE_MMAP_MAP_VARIABLE
1168 		  |MAP_VARIABLE
1169 #endif
1170 		  /*|MAP_NORESERVE*/
1171 		  ,*fd,0);
1172 
1173     if (memory == MAP_FAILED) {
1174       fprintf(stderr,"Error in access.c (3): Got mmap failure on file %s with len %jd from length %jd.  Error %d: %s\n",
1175 	      filename,*len,length,errno,strerror(errno));
1176       debug(printf("Got MAP_FAILED on file %s with len %zu from length %jd\n",filename,*len,length));
1177       memory = (void *) NULL;
1178 
1179     } else if (randomp == true) {
1180       debug(printf("Got mmap of %jd bytes at %p to %p\n",length,memory,memory+length-1));
1181 #ifdef HAVE_MADVISE
1182 #ifdef HAVE_MADVISE_MADV_RANDOM
1183       madvise(memory,*len,MADV_RANDOM);
1184 #endif
1185 #endif
1186 
1187     } else {
1188       debug(printf("Got mmap of %jd bytes at %p to %p\n",length,memory,memory+length-1));
1189 #ifdef HAVE_MADVISE
1190 #ifdef HAVE_MADVISE_MADV_DONTNEED
1191       madvise(memory,*len,MADV_DONTNEED);
1192 #endif
1193 #endif
1194     }
1195   }
1196 
1197   return memory;
1198 }
1199 #endif
1200 #endif	/* if 0 */
1201 
1202 
1203 #if 0
1204 /* All programs are read-only */
1205 #ifdef HAVE_MMAP
1206 /* Returns NULL if mmap fails.  Bigendian conversion required */
1207 #ifdef HAVE_CADDR_T
1208 caddr_t
1209 #else
1210 void *
1211 #endif
1212 Access_mmap_offset_rw (int *remainder, int fd, size_t offset, size_t length, bool randomp) {
1213 #ifdef HAVE_CADDR_T
1214   caddr_t memory;
1215 #else
1216   void *memory;
1217 #endif
1218 
1219   if (length == 0) {
1220     abort();
1221   }
1222 
1223   *remainder = offset % get_pagesize();
1224   offset -= (size_t) *remainder;
1225   length += (size_t) *remainder;
1226 
1227   if (sizeof(size_t) <= 4 && length > MAX32BIT) {
1228     debug(printf("Too big to mmap\n"));
1229     memory = (void *) NULL;
1230   } else {
1231     memory = mmap(NULL,length,PROT_READ|PROT_WRITE,0
1232 #ifdef HAVE_MMAP_MAP_SHARED
1233 		  |MAP_SHARED
1234 #endif
1235 #ifdef HAVE_MMAP_MAP_FILE
1236 		  |MAP_FILE
1237 #endif
1238 #ifdef HAVE_MMAP_MAP_VARIABLE
1239 		  |MAP_VARIABLE
1240 #endif
1241 		  /*|MAP_NORESERVE*/
1242 		  ,fd,offset);
1243 
1244     if (memory == MAP_FAILED) {
1245       fprintf(stderr,"Error in access.c (4): Got mmap failure on offset %jd, length %jd.  Error %d: %s\n",
1246 	      offset,length,errno,strerror(errno));
1247       debug(printf("Got MAP_FAILED on offset %jd, length %zu\n",offset,length));
1248       memory = (void *) NULL;
1249 
1250     } else if (randomp == true) {
1251       debug(printf("Got mmap of %zu bytes at %p to %p\n",length,memory,memory+length-1));
1252 #ifdef HAVE_MADVISE
1253 #ifdef HAVE_MADVISE_MADV_RANDOM
1254       madvise(memory,length,MADV_RANDOM);
1255 #endif
1256 #endif
1257 
1258     } else {
1259       debug(printf("Got mmap of %zu bytes at %p to %p\n",length,memory,memory+length-1));
1260 #ifdef HAVE_MADVISE
1261 #ifdef HAVE_MADVISE_MADV_DONTNEED
1262       madvise(memory,length,MADV_DONTNEED);
1263 #endif
1264 #endif
1265     }
1266   }
1267 
1268   return memory;
1269 }
1270 #endif
1271 #endif	/* if 0 */
1272 
1273 
1274 
1275 #ifdef HAVE_MMAP
1276 
1277 #ifdef HAVE_CADDR_T
1278 caddr_t
1279 #else
1280 void *
1281 #endif
Access_mmap_and_preload(int * fd,size_t * len,int * npages,double * seconds,char * filename,size_t eltsize)1282 Access_mmap_and_preload (int *fd, size_t *len, int *npages, double *seconds, char *filename, size_t eltsize) {
1283   size_t length;
1284 #ifdef HAVE_CADDR_T
1285   caddr_t memory;
1286 #else
1287   void *memory;
1288 #endif
1289   int pagesize, indicesperpage;
1290   size_t totalindices, i;	/* Needs to handle uncompressed genomes > 2 gigabytes */
1291   int nzero = 0, npos = 0;
1292   Stopwatch_T stopwatch;
1293 
1294 
1295   if (filename == NULL) {
1296     abort();
1297 
1298   } else if ((*len = length = Access_filesize(filename)) == 0U) {
1299     fprintf(stderr,"Warning: file %s is empty\n",filename);
1300     *fd = open(filename,O_RDONLY,0764); /* Still need to initialize value */
1301     memory = (void *) NULL;
1302 
1303   } else if ((*fd = open(filename,O_RDONLY,0764)) < 0) {
1304     fprintf(stderr,"Error: can't open file %s with open for reading\n",filename);
1305     exit(9);
1306 
1307   } else if (sizeof(size_t) <= 4 && *len > MAX32BIT) {
1308     debug(printf("Too big to mmap\n"));
1309     *len = 0;
1310     *npages = 0;
1311     *seconds = 0.0;
1312     memory = (void *) NULL;
1313 
1314   } else {
1315     pagesize = get_pagesize();
1316 
1317     indicesperpage = pagesize/eltsize;
1318 
1319     Stopwatch_start(stopwatch = Stopwatch_new());
1320 
1321     memory = mmap(NULL,length,PROT_READ,0
1322 #ifdef HAVE_MMAP_MAP_PRIVATE
1323 		  |MAP_PRIVATE
1324 #endif
1325 #ifdef HAVE_MMAP_MAP_FILE
1326 		  |MAP_FILE
1327 #endif
1328 #ifdef HAVE_MMAP_MAP_VARIABLE
1329 		  |MAP_VARIABLE
1330 #endif
1331 		  /*|MAP_NORESERVE*/
1332 		  ,*fd,0);
1333 
1334     if (memory == MAP_FAILED) {
1335       fprintf(stderr,"Error in access.c (5): Got mmap failure on file %s with len %jd from length %jd.  Error %d: %s\n",
1336 	      filename,*len,length,errno,strerror(errno));
1337       debug(printf("Got MAP_FAILED on file %s with len %jd from length %zu\n",filename,*len,length));
1338       memory = (void *) NULL;
1339       Stopwatch_stop(stopwatch);
1340       Stopwatch_free(&stopwatch);
1341 
1342     } else {
1343       /* Touch all pages */
1344       debug(printf("Got mmap of %zu bytes at %p to %p\n",length,memory,memory+length-1));
1345 #ifdef HAVE_MADVISE
1346 #ifdef HAVE_MADVISE_MADV_WILLNEED
1347       madvise(memory,*len,MADV_WILLNEED);
1348 #endif
1349 #endif
1350       totalindices = (*len)/eltsize;
1351       fprintf(stderr,"...");
1352       for (i = 0; i < totalindices; i += indicesperpage) {
1353 	if (((char *) memory)[i] == 0) {
1354 	  nzero++;
1355 #if 0
1356 	  if (i % 10000 == 0) {
1357 	    fprintf(stderr,",");
1358 	  }
1359 #endif
1360 	} else {
1361 	  npos++;
1362 	}
1363 #if 0
1364 	if (i % 10000 == 0) {
1365 	  fprintf(stderr,".");
1366 	}
1367 #endif
1368       }
1369       *npages = nzero + npos;
1370       *seconds = Stopwatch_stop(stopwatch);
1371       Stopwatch_free(&stopwatch);
1372     }
1373   }
1374 
1375   return memory;
1376 }
1377 #endif
1378 
1379 
1380