1 /*  $Id: ct_ncbimem.cpp 598667 2019-12-12 13:12:27Z gouriano $
2 * ===========================================================================
3 *
4 *                            PUBLIC DOMAIN NOTICE
5 *               National Center for Biotechnology Information
6 *
7 *  This software/database is a "United States Government Work" under the
8 *  terms of the United States Copyright Act.  It was written as part of
9 *  the author's official duties as a United States Government employee and
10 *  thus cannot be copyrighted.  This software/database is freely available
11 *  to the public for use. The National Library of Medicine and the U.S.
12 *  Government have not placed any restriction on its use or reproduction.
13 *
14 *  Although all reasonable efforts have been taken to ensure the accuracy
15 *  and reliability of the software and data, the NLM and the U.S.
16 *  Government do not and cannot warrant the performance or results that
17 *  may be obtained by using this software or data. The NLM and the U.S.
18 *  Government disclaim all warranties, express or implied, including
19 *  warranties of performance, merchantability or fitness for any particular
20 *  purpose.
21 *
22 *  Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * File Name:  ncbimem.c
27 *
28 * Author:  Gish, Kans, Ostell, Schuler
29 *
30 * Version Creation Date:   6/4/91
31 *
32 * C Tolkit Revision: 6.30
33 *
34 * File Description:
35 *   	portable memory handlers for Mac, PC, Unix
36 *
37 * ==========================================================================
38 */
39 
40 #include <ncbi_pch.hpp>
41 #include <corelib/ncbifile.hpp>
42 #include <corelib/ncbistr.hpp>
43 #include <ctools/ctransition/ncbimem.hpp>
44 #include <ctools/ctransition/ncbistr.hpp>
45 #include <ctools/ctransition/ncbierr.hpp>
46 
47 BEGIN_CTRANSITION_SCOPE
48 
49 
50 #ifdef OS_UNIX
51 #ifndef OS_UNIX_BEOS
52 /*#define USE_SETHEAPLIMIT*/
53 #undef USE_SETHEAPLIMIT
54 #endif
55 #endif
56 
57 /* ! -- disable */
58 #undef USE_SETHEAPLIMIT
59 
60 #ifdef USE_SETHEAPLIMIT
61 //#include <ncbithr.h>
62 #endif
63 
64 /*#include <ncbiwin.h>*/
65 
66 /* Used for UNIX memory-mapping. */
67 #ifdef MMAP_AVAIL
68 #  ifdef OS_UNIX_LINUX
69 /*   MADV_*** constants are not defined on Linux otherwise */
70 /*#    define __USE_BSD*/
71 #  endif
72 #  include <sys/mman.h>
73 #  ifdef OS_UNIX_AIX
74 #    include <fcntl.h>
75 #  else
76 #    include <sys/fcntl.h>
77 #  endif
78 #  ifndef MAP_FAILED
79 #    define MAP_FAILED ((void *) -1)
80 #  endif
81 #endif
82 
83 #ifdef USE_SETHEAPLIMIT
84 #include <sys/resource.h>
85 #endif
86 
87 
88 
89 short g_bBadPtr;
90 
91 static const char * _msgMemory  = "Ran out of memory";
92 
93 
Nlm_CallocViaMalloc(size_t n_elem,size_t item_size)94 NLM_EXTERN void* Nlm_CallocViaMalloc(size_t n_elem, size_t item_size)
95 {
96   size_t size = n_elem * item_size;
97   void*  ptr = Nlm_Malloc(size);
98   if ( ptr )
99     Nlm_MemSet(ptr, 0, size);
100   return ptr;
101 }
102 
103 
104 
105 #ifdef USE_SETHEAPLIMIT
106 static size_t s_SetHeapLimit_Curr = 0;
107 static size_t s_SetHeapLimit_Add  = 0;
108 static size_t s_SetHeapLimit_Max  = 0;
109 static TNlmMutex s_SetHeapLimit_Mutex;
110 
Nlm_SetHeapLimit(size_t curr,size_t add,size_t max)111 NLM_EXTERN Nlm_Boolean Nlm_SetHeapLimit(size_t curr, size_t add, size_t max)
112 {
113   Nlm_Boolean ok = FALSE;
114   struct rlimit rl;
115 
116   if (NlmMutexLockEx(&s_SetHeapLimit_Mutex) != 0)
117     return FALSE;
118 
119   if ( curr ) {
120     rl.rlim_cur = curr;
121     rl.rlim_max = RLIM_INFINITY;
122   }
123   else {
124     rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
125   }
126 
127   if (setrlimit(RLIMIT_DATA, &rl) == 0) {
128     s_SetHeapLimit_Curr = curr;
129     s_SetHeapLimit_Add  = add;
130     s_SetHeapLimit_Max  = max;
131     ok = TRUE;
132   }
133 
134   NlmMutexUnlock(s_SetHeapLimit_Mutex);
135   return ok;
136 }
137 
138 #else
Nlm_SetHeapLimit(size_t curr,size_t add,size_t max)139 NLM_EXTERN Nlm_Boolean Nlm_SetHeapLimit(size_t curr, size_t add, size_t max) {
140   return FALSE;
141 }
142 #endif /* USE_SETHEAPLIMIT */
143 
144 
145 typedef enum {
146   eA_Malloc,
147   eA_Calloc,
148   eA_Realloc
149 } EAllocator;
150 
151 /****************************************************************************
152  *
153  * s_MemAllocator(ptr, size, flags, allocator)
154  *   ptr       -- origin pointer(for eA_Realloc only)
155  *   size      -- number of bytes to allocate
156  *   flags     -- any of the following bits may be set
157  *      MGET_CLEAR     clear to zeros
158  *      MGET_ERRPOST   post error on allocaion failure
159  *   allocator -- method
160  *
161  * It is a generic routine for:
162  *   Nlm_MemGet(size, flags)
163  *   Nlm_MemNew(size)
164  *   Nlm_MemMore(ptr, size)
165  *   Nlm_MemExtend(ptr, size, oldsize)
166  *
167  ****************************************************************************/
168 
169 static Nlm_Boolean post_mssg_for_mem_fail = FALSE;
170 
171 extern void Nlm_SetMemFailFlag (Nlm_Boolean val);
Nlm_SetMemFailFlag(Nlm_Boolean val)172 extern void Nlm_SetMemFailFlag (Nlm_Boolean val)
173 
174 {
175   post_mssg_for_mem_fail = val;
176 }
177 
s_MemAllocator(void * ptr,size_t size,unsigned int flags,EAllocator allocator)178 static void* s_MemAllocator(void *ptr, size_t size,
179                             unsigned int flags, EAllocator allocator)
180 {
181   void *x_ptr = 0;
182 
183   switch ( allocator ) {
184   case eA_Malloc:
185     if ( !size )
186       return 0;
187     x_ptr = Nlm_Malloc(size);
188     break;
189   case eA_Calloc:
190     if ( !size )
191       return 0;
192     x_ptr = Nlm_Calloc(size, 1);
193     break;
194   case eA_Realloc:
195     if ( !ptr ) {
196       if (flags & MGET_ERRPOST)
197         ErrPostEx(SEV_WARNING, E_Programmer, 0, "Attempt to realloc NULL");
198       return 0;
199     }
200     if ( !size )
201       return Nlm_MemFree(ptr);
202 
203     x_ptr = Nlm_Realloc(ptr, size);
204     break;
205   }
206 
207 #ifdef USE_SETHEAPLIMIT
208   if (!x_ptr  &&  s_SetHeapLimit_Curr) {
209     NlmMutexLock(s_SetHeapLimit_Mutex);
210 
211     while (s_SetHeapLimit_Curr < s_SetHeapLimit_Max) {
212       struct rlimit rl;
213       size_t x_curr = s_SetHeapLimit_Curr + s_SetHeapLimit_Add;
214       if (x_curr > s_SetHeapLimit_Max)
215         x_curr = s_SetHeapLimit_Max;
216 
217       if (flags & MGET_ERRPOST) {
218         ErrPostEx(SEV_WARNING, E_NoMemory, 0,
219                   "Trying to allocate %ld bytes;  "
220                   "adjusting max.avail. heap size from %ld to %ld",
221                   (long)size, (long)s_SetHeapLimit_Curr, (long)x_curr);
222       }
223 
224       rl.rlim_cur = x_curr;
225       rl.rlim_max = RLIM_INFINITY;
226       if (setrlimit(RLIMIT_DATA, &rl) != 0)
227         break;
228 
229       s_SetHeapLimit_Curr = x_curr;
230 
231       switch ( allocator ) {
232       case eA_Malloc:
233         x_ptr = Nlm_Malloc(size);
234         break;
235       case eA_Calloc:
236         x_ptr = Nlm_Calloc(size, 1);
237         break;
238       case eA_Realloc:
239         x_ptr = Nlm_Realloc(ptr, size);
240         break;
241       }
242       if ( x_ptr )
243         break;
244     }
245 
246     NlmMutexUnlock(s_SetHeapLimit_Mutex);
247   }
248 #endif /* USE_SETHEAPLIMIT */
249 
250   if ( x_ptr ) {
251     if (flags & MGET_CLEAR)
252       memset(x_ptr, 0, size);
253   }
254   else if (flags & MGET_ERRPOST) {
255     if (post_mssg_for_mem_fail) {
256       Nlm_Message (MSG_OK, "Failed to allocate %ld bytes", (long)size);
257     }
258     ErrPostEx(SEV_FATAL, E_NoMemory, 0,
259               "Failed to allocate %ld bytes", (long)size);
260   }
261 
262   return x_ptr;
263 }
264 
265 
Nlm_MemGet(size_t size,unsigned int flags)266 NLM_EXTERN void* LIBCALL Nlm_MemGet(size_t size, unsigned int flags)
267 {
268   return s_MemAllocator(0, size, flags, eA_Malloc);
269 }
270 
Nlm_MemNew(size_t size)271 NLM_EXTERN void* LIBCALL Nlm_MemNew(size_t size)
272 {
273   return s_MemAllocator(0, size, MGET_ERRPOST, eA_Calloc);
274 }
275 
Nlm_MemMore(void * ptr,size_t size)276 NLM_EXTERN void* LIBCALL Nlm_MemMore(void *ptr, size_t size)
277 {
278   return s_MemAllocator(ptr, size, MGET_ERRPOST, eA_Realloc);
279 }
280 
Nlm_MemExtend(void * ptr,size_t size,size_t oldsize)281 NLM_EXTERN void* LIBCALL Nlm_MemExtend(void *ptr, size_t size, size_t oldsize)
282 {
283 	void *x_ptr = s_MemAllocator(ptr, size, MGET_ERRPOST, eA_Realloc);
284 	if (x_ptr  &&  size > oldsize)
285 		memset((char*)x_ptr + oldsize, 0, size - oldsize);
286 
287 	return x_ptr;
288 }
289 
290 
291 /*****************************************************************************
292 *
293 *   Nlm_MemFree(ptr)
294 *   	frees allocated memory
295 *
296 *****************************************************************************/
297 
Nlm_MemFree(void * ptr)298 NLM_EXTERN void * LIBCALL  Nlm_MemFree (void *ptr)
299 {
300     if (ptr) {
301         free(ptr);
302     }
303     return NULL;
304 }
305 
306 
307 #if defined(_DEBUG)  &&  defined(OS_MSWIN)
Nlm_MemFreeTrace(void * ptr,const char * module,const char * filename,int linenum)308 NLM_EXTERN void * LIBCALL  Nlm_MemFreeTrace (void *ptr, const char *module,
309 			const char *filename, int linenum)
310 {
311 	if (ptr != NULL) {
312 		free(ptr);
313 		if (g_bBadPtr) {
314 			ErrPostEx(SEV_WARNING,E_Programmer,0,
315 			          "MemFree: attempt to free invalid pointer");
316 		}
317 	}
318 	return NULL;
319 }
320 #endif
321 
322 
323 /*****************************************************************************
324 *
325 *    void Nlm_MemCopy(Pointer to, Pointer from, Uint4 bytes)
326 *       WARNING: no check on overlapping regions
327 *
328 *****************************************************************************/
329 
Nlm_MemCopy(void * dst,const void * src,size_t bytes)330 NLM_EXTERN void * LIBCALL  Nlm_MemCopy (void *dst, const void *src, size_t bytes)
331 {
332     return (dst&&src) ? Nlm_MemCpy (dst, src, bytes) : NULL;
333 }
334 
335 /*****************************************************************************
336 *
337 *    void Nlm_MemDup (Pointer orig, Uint4 bytes)
338 *       Duplicate the region of memory pointed to by 'orig' for 'size' length
339 *
340 *****************************************************************************/
341 
Nlm_MemDup(const void * orig,size_t size)342 NLM_EXTERN void * LIBCALL  Nlm_MemDup (const void *orig, size_t size)
343 {
344 	Nlm_VoidPtr	copy;
345 
346     if (!orig || !size) {
347         return NULL;
348     }
349     copy = Nlm_Malloc(size);
350     if (!copy) {
351         ErrPostEx(SEV_FATAL, E_NoMemory, 0, _msgMemory);
352         return NULL;
353     }
354 	Nlm_MemCpy(copy, orig, size);
355     return copy;
356 }
357 
358 /*****************************************************************************
359 *
360 *    void Nlm_MemMove (Pointer to, Pointer from, Uint4 bytes)
361 *       This code will work on overlapping regions
362 *
363 *****************************************************************************/
364 
Nlm_MemMove(void * dst,const void * src,size_t bytes)365 NLM_EXTERN void * LIBCALL  Nlm_MemMove (void * dst, const void *src, size_t bytes)
366 {
367 	register char *dest = (char*) dst;
368 	register const char *sorc = (const char*) src;
369 
370 	if (dest > sorc) {
371 		sorc += bytes;
372 		dest += bytes;
373 		while (bytes-- != 0) {
374 			*--dest = *--sorc;
375 		}
376 		} else {
377 		while (bytes-- != 0) {
378 			*dest++ = *sorc++;
379 		}
380 	}
381 	return dst;
382 }
383 
384 /*****************************************************************************
385 *
386 *   void Nlm_MemFill(to, value, bytes)
387 *   	set a block of memory to a value
388 *
389 *****************************************************************************/
390 
Nlm_MemFill(void * buf,int value,size_t bytes)391 NLM_EXTERN void * LIBCALL  Nlm_MemFill (void *buf, int value, size_t bytes)
392 {
393     return  buf ? Nlm_MemSet (buf, value, bytes) : NULL;
394 }
395 
396 
397 /*****************************************************************************
398 *
399 *   void Nlm_MemSearch(Pointer where, where_size, Pointer what, what_size)
400 *   	search a position one block of data into another
401 *
402 *****************************************************************************/
403 
Nlm_MemSearch(const void * where,size_t where_size,const void * what,size_t what_size)404 NLM_EXTERN size_t LIBCALL Nlm_MemSearch(const void* where, size_t where_size,
405                                         const void* what, size_t what_size)
406 {
407 	size_t i, rbound, pos;
408 
409 	rbound = where_size - what_size;
410 	pos = (size_t)-1;
411     i = 0;
412 	if (where_size  &&  what_size  &&  where_size >= what_size) {
413 		while ((i <= rbound)  &&  (pos == (size_t)-1)) {
414 			if (memcmp((char*)where + i, what, what_size)==0)
415                 pos = i;
416             else
417                 i++;
418 		}
419 	}
420 	return pos;
421 }
422 
423 
424 #if 0
425 #if defined(OS_MAC) || defined(OS_UNIX_DARWIN) || defined(OS_MSWIN) || defined(MSC_VIRT)
426 /***** Handle functions are for Macintosh and Windows only *****/
427 /***** or Microsoft virtual memory manager ****/
428 
429 static char * _msgNullHnd = "NULL handle passed as an argument";
430 
431 #ifdef MSC_VIRT
432 Nlm_Boolean wrote_to_handle;   /* used by ncbibs write routines */
433 #endif
434 
435 /*****************************************************************************
436 *
437 *   Nlm_HandGet(size, clear_out)
438 *   	returns handle to allocated memory
439 *       if (clear_out) clear memory to 0
440 *
441 *****************************************************************************/
442 
443 NLM_EXTERN Nlm_Handle LIBCALL  Nlm_HandGet (size_t size, Nlm_Boolean clear_out)
444 
445 {
446     Nlm_VoidPtr ptr;
447     Nlm_Handle  hnd;
448 
449     if (size == 0) return NULL;
450 
451 #if defined(OS_MAC) || defined(OS_UNIX_DARWIN)
452     hnd = (Nlm_Handle) NewHandle (size);
453 #endif
454 
455 #ifdef OS_MSWIN
456 #ifdef _DLL
457 #ifdef WIN32
458     hnd = (Nlm_Handle) HeapAlloc(GetProcessHeap(), 0, size);
459 #else
460     hnd = (Nlm_Handle) GlobalAlloc (GMEM_MOVEABLE, size);
461 #endif
462 #else
463     hnd = (Nlm_Handle) malloc (size);
464 #endif
465 #endif
466 
467 #ifdef MSC_VIRT
468 	hnd = (Nlm_Handle) _vmalloc ((unsigned long)size);
469 #endif
470 
471     if (hnd == NULL)
472     	ErrPostEx(SEV_FATAL,E_NoMemory,0,_msgMemory);
473 
474     else if (clear_out)	{
475 #ifdef MSC_VIRT
476 		wrote_to_handle = TRUE;
477 #endif
478         if ((ptr = HandLock (hnd)) != NULL)
479             Nlm_MemSet (ptr, 0, size);
480         HandUnlock (hnd);
481     }
482 
483     return  hnd;
484 }
485 
486 
487 /*****************************************************************************
488 *
489 *   Nlm_HandNew(size)
490 *
491 *****************************************************************************/
492 
493 NLM_EXTERN Nlm_Handle LIBCALL  Nlm_HandNew (size_t size)
494 
495 {
496     Nlm_Handle  hnd;
497 
498     if (size == 0)  return NULL;
499 
500     if ((hnd = HandGet (size, TRUE)) == NULL)
501     	ErrPostEx(SEV_FATAL,E_NoMemory,0,_msgMemory);
502 
503     return hnd;
504 }
505 
506 /*****************************************************************************
507 *
508 *   Nlm_HandMore(hnd, size)
509 *
510 *****************************************************************************/
511 
512 NLM_EXTERN Nlm_Handle LIBCALL  Nlm_HandMore (Nlm_Handle hnd, size_t size)
513 
514 {
515     Nlm_Handle  hnd2;
516 
517 	if (size == 0) {
518 		Nlm_HandFree (hnd);
519 		return NULL;
520 	}
521 
522     if (hnd == NULL) {
523     	ErrPostEx(SEV_WARNING,E_Programmer,0,"HandMore: %s", _msgNullHnd);
524 		return NULL;
525     }
526 
527 #if defined(OS_MAC) || defined(OS_UNIX_DARWIN)
528     SetHandleSize ((Handle)hnd, (Size)size);
529     hnd2 = hnd;
530     if (MemError() != noErr)
531         hnd2 = NULL;
532 #endif
533 
534 #ifdef OS_MSWIN
535 #ifdef _DLL
536 #ifdef WIN32
537     hnd2 = (Nlm_Handle) HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, hnd, size);
538 #else
539     hnd2 = (Nlm_Handle) GlobalReAlloc ((HANDLE) hnd, size, GHND);
540 #endif
541 #else
542     hnd2 = (Nlm_Handle) realloc (hnd, size);
543 #endif
544 #endif
545 
546 #ifdef MSC_VIRT
547 	hnd2 = (Nlm_Handle) _vrealloc ((_vmhnd_t)hnd, (unsigned long)size);
548 #endif
549 
550     if (hnd2 == NULL)
551     	ErrPostEx(SEV_FATAL,E_NoMemory,0,_msgMemory);
552 
553     return  hnd2;
554 }
555 
556 
557 /*****************************************************************************
558 *
559 *   Nlm_HandFree (hnd)
560 *
561 *****************************************************************************/
562 
563 NLM_EXTERN Nlm_Handle LIBCALL  Nlm_HandFree (Nlm_Handle hnd)
564 {
565 #ifdef MSC_VIRT
566 	_vmhnd_t x;
567 #endif
568 
569     if (hnd) {
570 
571 #if defined(OS_MAC) || defined(OS_UNIX_DARWIN)
572         DisposeHandle ((Handle) hnd);
573 #endif
574 
575 #ifdef OS_MSWIN
576 #ifdef _DLL
577 #ifdef WIN32
578         HeapFree(GetProcessHeap(), 0, (HANDLE) hnd);
579 #else
580         GlobalFree ((HANDLE) hnd);
581 #endif
582 #else
583         free (hnd);
584 #endif
585 #endif
586 
587 #ifdef MSC_VIRT
588 		x = (_vmhnd_t)hnd;
589 		while (_vlockcnt(x))
590 			_vunlock(x, _VM_CLEAN);
591 		_vfree(x);
592 #endif
593     }
594     else
595     	ErrPostEx(SEV_WARNING,E_Programmer,0,"HandFree: %s", _msgNullHnd);
596 
597     return NULL;
598 }
599 
600 
601 /*****************************************************************************
602 *
603 *   Nlm_HandLock (hnd)
604 *
605 *****************************************************************************/
606 
607 NLM_EXTERN Nlm_VoidPtr LIBCALL  Nlm_HandLock (Nlm_Handle hnd)
608 {
609     Nlm_VoidPtr ptr;
610 
611     if (hnd == NULL) {
612     	ErrPostEx(SEV_WARNING,E_Programmer,0,"HandLock: %s", _msgNullHnd);
613         return NULL;
614     }
615 
616 #if defined(OS_MAC) || defined(OS_UNIX_DARWIN)
617     HLock ((Handle) hnd);
618     ptr = *((Handle) hnd);
619 #endif
620 
621 #ifdef OS_MSWIN
622 #ifdef _DLL
623 #ifdef WIN32
624     ptr = hnd;
625 #else
626     ptr = GlobalLock ((HANDLE) hnd);
627 #endif
628 #else
629     ptr = hnd;
630 #endif
631 #endif
632 
633 #ifdef MSC_VIRT
634 	ptr = _vlock((_vmhnd_t) hnd);
635 #endif
636 
637     return  ptr;
638 }
639 
640 /*****************************************************************************
641 *
642 *   Nlm_HandUnlock(hnd)
643 *
644 *****************************************************************************/
645 
646 NLM_EXTERN Nlm_VoidPtr LIBCALL  Nlm_HandUnlock (Nlm_Handle hnd)
647 {
648 #ifdef MSC_VIRT
649 	int dirty = _VM_CLEAN;
650 #endif
651 
652     if (hnd == NULL)
653     	ErrPostEx(SEV_WARNING,E_Programmer,0,"HandUnlock: %s", _msgNullHnd);
654     else {
655 #if defined(OS_MAC) || defined(OS_UNIX_DARWIN)
656         HUnlock ((Handle) hnd);
657 #endif
658 
659 #ifdef OS_MSWIN
660 #ifdef _DLL
661 #ifdef WIN32
662         /* nothing */
663 #else
664         GlobalUnlock ((HANDLE) hnd);
665 #endif
666 #else
667         /* nothing */
668 #endif
669 #endif
670 
671 #ifdef MSC_VIRT
672 		if (wrote_to_handle == TRUE)
673 			dirty = _VM_DIRTY;
674 		_vunlock ((_vmhnd_t) hnd, dirty);  /* always assume dirty */
675 		wrote_to_handle = FALSE;
676 #endif
677     }
678 
679     return NULL;
680 }
681 
682 #endif /* Mac or Win */
683 #endif /*0*/
684 
685 
686 
687 #ifdef _WINDLL
688 /*****************************************************************************
689 *
690 *   Windows DLL-specific functions (shared memory)
691 *
692 *   dll_Malloc
693 *   dll_Calloc	(not yet)
694 *   dll_Realloc	(not yet)
695 *   dll_Free
696 *
697 *****************************************************************************/
698 
699 
dll_Malloc(size_t bytes)700 void * dll_Malloc (size_t bytes)
701 {
702 	HGLOBAL hMem;
703 	void *pMem;
704 
705 	if (bytes >0 && (hMem = GlobalAlloc(GMEM_DDESHARE,bytes)))
706 	{
707 		if (pMem = GlobalLock(hMem))
708 			return pMem;
709 		else
710 			GlobalFree(hMem);
711 	}
712 
713 	TRACE("dll_Malloc(%ld) failed\n",bytes);
714 	return NULL;
715 }
716 
dll_Free(void * pMem)717 void   dll_Free (void *pMem)
718 {
719 	HGLOBAL hMem = GlobalHandle(pMem);
720 	GlobalUnlock(hMem);
721 	GlobalFree(hMem);
722 }
723 #endif /* _WINDLL */
724 
725 
726 /*********************************************************************
727 *	Function to test whether memory-mapping is available.
728 *
729 *	returns TRUE if it is supported by NCBI routines.
730 *********************************************************************/
731 
Nlm_MemMapAvailable(void)732 NLM_EXTERN Nlm_Boolean Nlm_MemMapAvailable(void)
733 {
734 #if defined(MMAP_AVAIL) || defined(WIN32)
735   return TRUE;
736 #else
737   return FALSE;
738 #endif
739 }
740 
741 
Nlm_MemMapInit(const Nlm_Char PNTR name)742 NLM_EXTERN Nlm_MemMapPtr Nlm_MemMapInit(const Nlm_Char PNTR name)
743 {
744   Nlm_MemMapPtr mem_mapp;
745   if (!Nlm_MemMapAvailable()  ||  !name  ||  !*name  ||
746       (mem_mapp = (Nlm_MemMapPtr)Nlm_MemNew(sizeof(Nlm_MemMap))) == NULL)
747     return NULL;
748 
749   for (;;) {{ /* (quasi-TRY block) */
750     if ((mem_mapp->file_size = NCBI_NS_NCBI::CFile(name).GetLength()) < 0)
751       break;
752 
753     if (mem_mapp->file_size == 0) /* Special case */
754       return mem_mapp;
755 
756 #ifdef WIN32
757     {{
758       char x_name[MAX_PATH], *str;
759       Nlm_StringNCpy_0(x_name, name, sizeof(x_name));
760       for (str = x_name;  *str;  str++)
761         if (*str == '\\')
762           *str = '/';  /* name of a file-mapping object cannot contain '\' */
763 
764       if ( !(mem_mapp->hMap =
765              OpenFileMapping(FILE_MAP_READ, FALSE, _T_XCSTRING(x_name))) )
766         { /* If failed to attach to an existing file-mapping object then
767            * create a new one(based on the specified file) */
768           HANDLE hFile= CreateFile(_T_XCSTRING(name), GENERIC_READ, FILE_SHARE_READ, NULL,
769                                    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
770           if (hFile == INVALID_HANDLE_VALUE)
771             break;
772 
773           mem_mapp->hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY,
774                                              0, 0, _T_XCSTRING(x_name));
775           CloseHandle( hFile );
776           if ( !mem_mapp->hMap )
777             break;
778         }
779 
780       if ( !(mem_mapp->mmp_begin = (Nlm_CharPtr)
781              MapViewOfFile(mem_mapp->hMap, FILE_MAP_READ,
782                            0, 0, mem_mapp->file_size)) ) {
783         CloseHandle( mem_mapp->hMap );
784         break;
785       }
786     }}
787 
788 #elif defined(MMAP_AVAIL)
789     {{  /* UNIX memory mapping. */
790       int fd = open(name, O_RDONLY);
791       if (fd < 0)
792         break;
793 
794       mem_mapp->mmp_begin = (Nlm_CharPtr) mmap(NULL, mem_mapp->file_size,
795                                                PROT_READ, MAP_PRIVATE, fd, 0);
796       close(fd);
797       if ((void*) mem_mapp->mmp_begin == (void*) MAP_FAILED)
798         break;
799     }}
800 #endif
801 
802     /* Success */
803     return mem_mapp;
804   }}
805 
806   /* Error;  cleanup */
807   Nlm_MemFree(mem_mapp);
808   return NULL;
809 }
810 
811 
Nlm_MemMapFini(Nlm_MemMapPtr mem_mapp)812 NLM_EXTERN void Nlm_MemMapFini(Nlm_MemMapPtr mem_mapp)
813 {
814   if ( !mem_mapp )
815     return;
816 
817 #ifdef WIN32
818   UnmapViewOfFile( mem_mapp->mmp_begin );
819   if ( mem_mapp->hMap )
820     CloseHandle( mem_mapp->hMap );
821 #elif defined(MMAP_AVAIL)
822   munmap(mem_mapp->mmp_begin, mem_mapp->file_size);
823 #endif
824 
825   Nlm_MemFree(mem_mapp);
826 }
827 
828 
Nlm_MemMapAdvise(void * addr,size_t len,EMemMapAdvise advise)829 NLM_EXTERN Nlm_Boolean Nlm_MemMapAdvise(void* addr, size_t len, EMemMapAdvise advise)
830 {
831 #if defined(HAVE_MADVISE) && defined(MADV_NORMAL)
832   int adv;
833   if (!addr || !len) {
834     return FALSE;
835   }
836   switch (advise) {
837 	case eMMA_Random:
838 	  adv = MADV_RANDOM;     break;
839 	case eMMA_Sequential:
840       adv = MADV_SEQUENTIAL; break;
841 	case eMMA_WillNeed:
842 	  adv = MADV_WILLNEED;   break;
843 	case eMMA_DontNeed:
844 	  adv = MADV_DONTNEED;   break;
845 	default:
846 	  adv = MADV_NORMAL;
847   }
848   /* Conversion type of "addr" to char* -- Sun Solaris fix */
849   return madvise((char*)addr, len, adv) == 0;
850 #else
851   return TRUE;
852 #endif
853 }
854 
855 
Nlm_MemMapAdvisePtr(Nlm_MemMapPtr ptr,EMemMapAdvise advise)856 NLM_EXTERN Nlm_Boolean Nlm_MemMapAdvisePtr(Nlm_MemMapPtr ptr, EMemMapAdvise advise)
857 {
858 #if defined(HAVE_MADVISE) && defined(MADV_NORMAL)
859   return ptr ? Nlm_MemMapAdvise(ptr->mmp_begin, ptr->file_size, advise) : FALSE;
860 #else
861   return TRUE;
862 #endif
863 }
864 
865 
866 END_CTRANSITION_SCOPE
867