/* vi:set ts=8 sts=4 sw=4: * * VIM - Vi IMproved by Bram Moolenaar * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. * See README.txt for an overview of the Vim source code. */ /* * memfile.c: Contains the functions for handling blocks of memory which can * be stored in a file. This is the implementation of a sort of virtual memory. * * A memfile consists of a sequence of blocks. The blocks numbered from 0 * upwards have been assigned a place in the actual file. The block number * is equal to the page number in the file. The * blocks with negative numbers are currently in memory only. They can be * assigned a place in the file when too much memory is being used. At that * moment they get a new, positive, number. A list is used for translation of * negative to positive numbers. * * The size of a block is a multiple of a page size, normally the page size of * the device the file is on. Most blocks are 1 page long. A Block of multiple * pages is used for a line that does not fit in a single page. * * Each block can be in memory and/or in a file. The block stays in memory * as long as it is locked. If it is no longer locked it can be swapped out to * the file. It is only written to the file if it has been changed. * * Under normal operation the file is created when opening the memory file and * deleted when closing the memory file. Only with recovery an existing memory * file is opened. */ #if defined MSDOS || defined(WIN32) || defined(_WIN64)# include "vimio.h" /* for lseek(), must be before vim.h */#endif #include "vim.h" #ifdef HAVE_FCNTL_H# include <fcntl.h>#endif /* * Some systems have the page size in statfs.f_bsize, some in stat.st_blksize */#ifdef HAVE_ST_BLKSIZE# define STATFS stat# define F_BSIZE st_blksize# define fstatfs(fd, buf, len, nul) mch_fstat((fd), (buf))#else# ifdef HAVE_SYS_STATFS_H# include <sys/statfs.h># define STATFS statfs# define F_BSIZE f_bsize# ifdef __MINT__ /* do we still need this? */# define fstatfs(fd, buf, len, nul) mch_fstat((fd), (buf))# endif# endif#endif /* * for Amiga Dos 2.0x we use Flush */#ifdef AMIGA# ifdef FEAT_ARPextern int dos2; /* this is in os_amiga.c */# endif# ifdef SASC# include <proto/dos.h># include <ios1.h> /* for chkufb() */# endif#endif #define MEMFILE_PAGE_SIZE 4096 /* default page size */ static long_u total_mem_used = 0; /* total memory used for memfiles */ static void mf_ins_hash __ARGS((memfile_T *, bhdr_T *));static void mf_rem_hash __ARGS((memfile_T *, bhdr_T *));static bhdr_T *mf_find_hash __ARGS((memfile_T *, blocknr_T));static void mf_ins_used __ARGS((memfile_T *, bhdr_T *));static void mf_rem_used __ARGS((memfile_T *, bhdr_T *));static bhdr_T *mf_release __ARGS((memfile_T *, int));static bhdr_T *mf_alloc_bhdr __ARGS((memfile_T *, int));static void mf_free_bhdr __ARGS((bhdr_T *));static void mf_ins_free __ARGS((memfile_T *, bhdr_T *));static bhdr_T *mf_rem_free __ARGS((memfile_T *));static int mf_read __ARGS((memfile_T *, bhdr_T *));static int mf_write __ARGS((memfile_T *, bhdr_T *));static int mf_trans_add __ARGS((memfile_T *, bhdr_T *));static void mf_do_open __ARGS((memfile_T *, char_u *, int)); /* * The functions for using a memfile: * * mf_open() open a new or existing memfile * mf_open_file() open a swap file for an existing memfile * mf_close() close (and delete) a memfile * mf_new() create a new block in a memfile and lock it * mf_get() get an existing block and lock it * mf_put() unlock a block, may be marked for writing * mf_free() remove a block * mf_sync() sync changed parts of memfile to disk * mf_release_all() release as much memory as possible * mf_trans_del() may translate negative to positive block number * mf_fullname() make file name full path (use before first :cd) */ /* * Open an existing or new memory block file. * * fname: name of file to use (NULL means no file at all) * Note: fname must have been allocated, it is not copied! * If opening the file fails, fname is freed. * flags: flags for open() call * * If fname != NULL and file cannot be opened, fail. * * return value: identifier for this memory block file. */ memfile_T *mf_open(fname, flags) char_u *fname; int flags;{ memfile_T *mfp; int i; off_t size;#if defined(STATFS) && defined(UNIX) && !defined(__QNX__)# define USE_FSTATFS struct STATFS stf;#endif if ((mfp = (memfile_T *)alloc((unsigned)sizeof(memfile_T))) == NULL) return NULL; if (fname == NULL) /* no file for this memfile, use memory only */ { mfp->mf_fname = NULL; mfp->mf_ffname = NULL; mfp->mf_fd = -1; } else { mf_do_open(mfp, fname, flags); /* try to open the file */ /* if the file cannot be opened, return here */ if (mfp->mf_fd < 0) { vim_free(mfp); return NULL; } } mfp->mf_free_first = NULL; /* free list is empty */ mfp->mf_used_first = NULL; /* used list is empty */ mfp->mf_used_last = NULL; mfp->mf_dirty = FALSE; mfp->mf_used_count = 0; for (i = 0; i < MEMHASHSIZE; ++i) { mfp->mf_hash[i] = NULL; /* hash lists are empty */ mfp->mf_trans[i] = NULL; /* trans lists are empty */ } mfp->mf_page_size = MEMFILE_PAGE_SIZE; #ifdef USE_FSTATFS /* * Try to set the page size equal to the block size of the device. * Speeds up I/O a lot. * When recovering, the actual block size will be retrieved from block 0 * in ml_recover(). The size used here may be wrong, therefore * mf_blocknr_max must be rounded up. */ if (mfp->mf_fd >= 0 && fstatfs(mfp->mf_fd, &stf, sizeof(struct statfs), 0) == 0 && stf.F_BSIZE >= MIN_SWAP_PAGE_SIZE && stf.F_BSIZE <= MAX_SWAP_PAGE_SIZE) mfp->mf_page_size = stf.F_BSIZE;#endif if (mfp->mf_fd < 0 || (flags & (O_TRUNC|O_EXCL)) || (size = lseek(mfp->mf_fd, (off_t)0L, SEEK_END)) <= 0) mfp->mf_blocknr_max = 0; /* no file or empty file */ else mfp->mf_blocknr_max = (blocknr_T)((size + mfp->mf_page_size - 1) / mfp->mf_page_size); mfp->mf_blocknr_min = -1; mfp->mf_neg_count = 0; mfp->mf_infile_count = mfp->mf_blocknr_max; /* * Compute maximum number of pages ('maxmem' is in Kbyte): * 'mammem' * 1Kbyte / page-size-in-bytes. * Avoid overflow by first reducing page size as much as possible. */ { int shift = 10; unsigned page_size = mfp->mf_page_size; while (shift > 0 && (page_size & 1) == 0) { page_size = page_size >> 1; --shift; } mfp->mf_used_count_max = (p_mm << shift) / page_size; if (mfp->mf_used_count_max < 10) mfp->mf_used_count_max = 10; } return mfp;} /* * Open a file for an existing memfile. Used when updatecount set from 0 to * some value. * If the file already exists, this fails. * "fname" is the name of file to use (NULL means no file at all) * Note: "fname" must have been allocated, it is not copied! If opening the * file fails, "fname" is freed. * * return value: FAIL if file could not be opened, OK otherwise */ intmf_open_file(mfp, fname) memfile_T *mfp; char_u *fname;{ mf_do_open(mfp, fname, O_RDWR|O_CREAT|O_EXCL); /* try to open the file */ if (mfp->mf_fd < 0) return FAIL; mfp->mf_dirty = TRUE; return OK;} /* * close a memory file and delete the associated file if 'del_file' is TRUE */ voidmf_close(mfp, del_file) memfile_T *mfp; int del_file;{ bhdr_T *hp, *nextp; NR_TRANS *tp, *tpnext; int i; if (mfp == NULL) /* safety check */ return; if (mfp->mf_fd >= 0) { if (close(mfp->mf_fd) < 0) EMSG(_(e_swapclose)); } if (del_file && mfp->mf_fname != NULL) mch_remove(mfp->mf_fname); /* free entries in used list */ for (hp = mfp->mf_used_first; hp != NULL; hp = nextp) { total_mem_used -= hp->bh_page_count * mfp->mf_page_size; nextp = hp->bh_next; mf_free_bhdr(hp); } while (mfp->mf_free_first != NULL) /* free entries in free list */ vim_free(mf_rem_free(mfp)); for (i = 0; i < MEMHASHSIZE; ++i) /* free entries in trans lists */ for (tp = mfp->mf_trans[i]; tp != NULL; tp = tpnext) { tpnext = tp->nt_next; vim_free(tp); } vim_free(mfp->mf_fname); vim_free(mfp->mf_ffname); vim_free(mfp);} /* * Close the swap file for a memfile. Used when 'swapfile' is reset. */ voidmf_close_file(buf, getlines) buf_T *buf; int getlines; /* get all lines into memory? */{ memfile_T *mfp; linenr_T lnum; mfp = buf->b_ml.ml_mfp; if (mfp == NULL || mfp->mf_fd < 0) /* nothing to close */ return; if (getlines) { /* get all blocks in memory by accessing all lines (clumsy!) */ mf_dont_release = TRUE; for (lnum = 1; lnum <= buf->b_ml.ml_line_count; ++lnum) (void)ml_get_buf(buf, lnum, FALSE); mf_dont_release = FALSE; /* TODO: should check if all blocks are really in core */ } if (close(mfp->mf_fd) < 0) /* close the file */ EMSG(_(e_swapclose)); mfp->mf_fd = -1; if (mfp->mf_fname != NULL) { mch_remove(mfp->mf_fname); /* delete the swap file */ vim_free(mfp->mf_fname); vim_free(mfp->mf_ffname); mfp->mf_fname = NULL; mfp->mf_ffname = NULL; }} /* * Set new size for a memfile. Used when block 0 of a swapfile has been read * and the size it indicates differs from what was guessed. */ voidmf_new_page_size(mfp, new_size) memfile_T *mfp; unsigned new_size;{ /* Correct the memory used for block 0 to the new size, because it will be * freed with that size later on. */ total_mem_used += new_size - mfp->mf_page_size; mfp->mf_page_size = new_size;} /* * get a new block * * negative: TRUE if negative block number desired (data block) */ bhdr_T *mf_new(mfp, negative, page_count) memfile_T *mfp; int negative; int page_count;{ bhdr_T *hp; /* new bhdr_T */ bhdr_T *freep; /* first block in free list */ char_u *p; /* * If we reached the maximum size for the used memory blocks, release one * If a bhdr_T is returned, use it and adjust the page_count if necessary. */ hp = mf_release(mfp, page_count); /* * Decide on the number to use: * If there is a free block, use its number. * Otherwise use mf_block_min for a negative number, mf_block_max for * a positive number. */ freep = mfp->mf_free_first; if (!negative && freep != NULL && freep->bh_page_count >= page_count) { /* * If the block in the free list has more pages, take only the number * of pages needed and allocate a new bhdr_T with data * * If the number of pages matches and mf_release() did not return a * bhdr_T, use the bhdr_T from the free list and allocate the data * * If the number of pages matches and mf_release() returned a bhdr_T, * just use the number and free the bhdr_T from the free list */ if (freep->bh_page_count > page_count) { if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL) return NULL; hp->bh_bnum = freep->bh_bnum; freep->bh_bnum += page_count; freep->bh_page_count -= page_count; } else if (hp == NULL) /* need to allocate memory for this block */ { if ((p = (char_u *)alloc(mfp->mf_page_size * page_count)) == NULL) return NULL; hp = mf_rem_free(mfp); hp->bh_data = p; } else /* use the number, remove entry from free list */ { freep = mf_rem_free(mfp); hp->bh_bnum = freep->bh_bnum; vim_free(freep); } } else /* get a new number */ { if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL) return NULL; if (negative) { hp->bh_bnum = mfp->mf_blocknr_min--; mfp->mf_neg_count++; } else { hp->bh_bnum = mfp->mf_blocknr_max; mfp->mf_blocknr_max += page_count; } } hp->bh_flags = BH_LOCKED | BH_DIRTY; /* new block is always dirty */ mfp->mf_dirty = TRUE; hp->bh_page_count = page_count; mf_ins_used(mfp, hp); mf_ins_hash(mfp, hp); /* * Init the data to all zero, to avoid reading uninitialized data. * This also avoids that the passwd file ends up in the swap file! */ (void)vim_memset((char *)(hp->bh_data), 0, (size_t)mfp->mf_page_size); return hp;} /* * get existing block 'nr' with 'page_count' pages * * Note: The caller should first check a negative nr with mf_trans_del() */ bhdr_T *mf_get(mfp, nr, page_count) memfile_T *mfp; blocknr_T nr; int page_count;{ bhdr_T *hp; /* doesn't exist */ if (nr >= mfp->mf_blocknr_max || nr <= mfp->mf_blocknr_min) return NULL; /* * see if it is in the cache */ hp = mf_find_hash(mfp, nr); if (hp == NULL) /* not in the hash list */ { if (nr < 0 || nr >= mfp->mf_infile_count) /* can't be in the file */ return NULL; /* could check here if the block is in the free list */ /* * Check if we need to flush an existing block. * If so, use that block. * If not, allocate a new block. */ hp = mf_release(mfp, page_count); if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL) return NULL; hp->bh_bnum = nr; hp->bh_flags = 0; hp->bh_page_count = page_count; if (mf_read(mfp, hp) == FAIL) /* cannot read the block! */ { mf_free_bhdr(hp); return NULL; } } else { mf_rem_used(mfp, hp); /* remove from list, insert in front below */ mf_rem_hash(mfp, hp); } hp->bh_flags |= BH_LOCKED; mf_ins_used(mfp, hp); /* put in front of used list */ mf_ins_hash(mfp, hp); /* put in front of hash list */ return hp;} /* * release the block *hp * * dirty: Block must be written to file later * infile: Block should be in file (needed for recovery) * * no return value, function cannot fail */ voidmf_put(mfp, hp, dirty, infile) memfile_T *mfp; bhdr_T *hp; int dirty; int infile;{ int flags;Lines 1–500 of 1350. Load more
/* vi:set ts=8 sts=4 sw=4: * * VIM - Vi IMproved by Bram Moolenaar * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. * See README.txt for an overview of the Vim source code. */ /* * memfile.c: Contains the functions for handling blocks of memory which can * be stored in a file. This is the implementation of a sort of virtual memory. * * A memfile consists of a sequence of blocks. The blocks numbered from 0 * upwards have been assigned a place in the actual file. The block number * is equal to the page number in the file. The * blocks with negative numbers are currently in memory only. They can be * assigned a place in the file when too much memory is being used. At that * moment they get a new, positive, number. A list is used for translation of * negative to positive numbers. * * The size of a block is a multiple of a page size, normally the page size of * the device the file is on. Most blocks are 1 page long. A Block of multiple * pages is used for a line that does not fit in a single page. * * Each block can be in memory and/or in a file. The block stays in memory * as long as it is locked. If it is no longer locked it can be swapped out to * the file. It is only written to the file if it has been changed. * * Under normal operation the file is created when opening the memory file and * deleted when closing the memory file. Only with recovery an existing memory * file is opened. */ #if defined MSDOS || defined(WIN32) || defined(_WIN64) # include "vimio.h" /* for lseek(), must be before vim.h */ #endif #include "vim.h" #ifdef HAVE_FCNTL_H # include <fcntl.h> #endif /* * Some systems have the page size in statfs.f_bsize, some in stat.st_blksize */ #ifdef HAVE_ST_BLKSIZE # define STATFS stat # define F_BSIZE st_blksize # define fstatfs(fd, buf, len, nul) mch_fstat((fd), (buf)) #else # ifdef HAVE_SYS_STATFS_H # include <sys/statfs.h> # define STATFS statfs # define F_BSIZE f_bsize # ifdef __MINT__ /* do we still need this? */ # define fstatfs(fd, buf, len, nul) mch_fstat((fd), (buf)) # endif # endif #endif /* * for Amiga Dos 2.0x we use Flush */ #ifdef AMIGA # ifdef FEAT_ARP extern int dos2; /* this is in os_amiga.c */ # endif # ifdef SASC # include <proto/dos.h> # include <ios1.h> /* for chkufb() */ # endif #endif #define MEMFILE_PAGE_SIZE 4096 /* default page size */ static long_u total_mem_used = 0; /* total memory used for memfiles */ static void mf_ins_hash __ARGS((memfile_T *, bhdr_T *)); static void mf_rem_hash __ARGS((memfile_T *, bhdr_T *)); static bhdr_T *mf_find_hash __ARGS((memfile_T *, blocknr_T)); static void mf_ins_used __ARGS((memfile_T *, bhdr_T *)); static void mf_rem_used __ARGS((memfile_T *, bhdr_T *)); static bhdr_T *mf_release __ARGS((memfile_T *, int)); static bhdr_T *mf_alloc_bhdr __ARGS((memfile_T *, int)); static void mf_free_bhdr __ARGS((bhdr_T *)); static void mf_ins_free __ARGS((memfile_T *, bhdr_T *)); static bhdr_T *mf_rem_free __ARGS((memfile_T *)); static int mf_read __ARGS((memfile_T *, bhdr_T *)); static int mf_write __ARGS((memfile_T *, bhdr_T *)); static int mf_trans_add __ARGS((memfile_T *, bhdr_T *)); static void mf_do_open __ARGS((memfile_T *, char_u *, int)); /* * The functions for using a memfile: * * mf_open() open a new or existing memfile * mf_open_file() open a swap file for an existing memfile * mf_close() close (and delete) a memfile * mf_new() create a new block in a memfile and lock it * mf_get() get an existing block and lock it * mf_put() unlock a block, may be marked for writing * mf_free() remove a block * mf_sync() sync changed parts of memfile to disk * mf_release_all() release as much memory as possible * mf_trans_del() may translate negative to positive block number * mf_fullname() make file name full path (use before first :cd) */ /* * Open an existing or new memory block file. * * fname: name of file to use (NULL means no file at all) * Note: fname must have been allocated, it is not copied! * If opening the file fails, fname is freed. * flags: flags for open() call * * If fname != NULL and file cannot be opened, fail. * * return value: identifier for this memory block file. */ memfile_T * mf_open(fname, flags) char_u *fname; int flags; { memfile_T *mfp; int i; off_t size; #if defined(STATFS) && defined(UNIX) && !defined(__QNX__) # define USE_FSTATFS struct STATFS stf; #endif if ((mfp = (memfile_T *)alloc((unsigned)sizeof(memfile_T))) == NULL) return NULL; if (fname == NULL) /* no file for this memfile, use memory only */ { mfp->mf_fname = NULL; mfp->mf_ffname = NULL; mfp->mf_fd = -1; } else { mf_do_open(mfp, fname, flags); /* try to open the file */ /* if the file cannot be opened, return here */ if (mfp->mf_fd < 0) { vim_free(mfp); return NULL; } } mfp->mf_free_first = NULL; /* free list is empty */ mfp->mf_used_first = NULL; /* used list is empty */ mfp->mf_used_last = NULL; mfp->mf_dirty = FALSE; mfp->mf_used_count = 0; for (i = 0; i < MEMHASHSIZE; ++i) { mfp->mf_hash[i] = NULL; /* hash lists are empty */ mfp->mf_trans[i] = NULL; /* trans lists are empty */ } mfp->mf_page_size = MEMFILE_PAGE_SIZE; #ifdef USE_FSTATFS /* * Try to set the page size equal to the block size of the device. * Speeds up I/O a lot. * When recovering, the actual block size will be retrieved from block 0 * in ml_recover(). The size used here may be wrong, therefore * mf_blocknr_max must be rounded up. */ if (mfp->mf_fd >= 0 && fstatfs(mfp->mf_fd, &stf, sizeof(struct statfs), 0) == 0 && stf.F_BSIZE >= MIN_SWAP_PAGE_SIZE && stf.F_BSIZE <= MAX_SWAP_PAGE_SIZE) mfp->mf_page_size = stf.F_BSIZE; #endif if (mfp->mf_fd < 0 || (flags & (O_TRUNC|O_EXCL)) || (size = lseek(mfp->mf_fd, (off_t)0L, SEEK_END)) <= 0) mfp->mf_blocknr_max = 0; /* no file or empty file */ else mfp->mf_blocknr_max = (blocknr_T)((size + mfp->mf_page_size - 1) / mfp->mf_page_size); mfp->mf_blocknr_min = -1; mfp->mf_neg_count = 0; mfp->mf_infile_count = mfp->mf_blocknr_max; /* * Compute maximum number of pages ('maxmem' is in Kbyte): * 'mammem' * 1Kbyte / page-size-in-bytes. * Avoid overflow by first reducing page size as much as possible. */ { int shift = 10; unsigned page_size = mfp->mf_page_size; while (shift > 0 && (page_size & 1) == 0) { page_size = page_size >> 1; --shift; } mfp->mf_used_count_max = (p_mm << shift) / page_size; if (mfp->mf_used_count_max < 10) mfp->mf_used_count_max = 10; } return mfp; } /* * Open a file for an existing memfile. Used when updatecount set from 0 to * some value. * If the file already exists, this fails. * "fname" is the name of file to use (NULL means no file at all) * Note: "fname" must have been allocated, it is not copied! If opening the * file fails, "fname" is freed. * * return value: FAIL if file could not be opened, OK otherwise */ int mf_open_file(mfp, fname) memfile_T *mfp; char_u *fname; { mf_do_open(mfp, fname, O_RDWR|O_CREAT|O_EXCL); /* try to open the file */ if (mfp->mf_fd < 0) return FAIL; mfp->mf_dirty = TRUE; return OK; } /* * close a memory file and delete the associated file if 'del_file' is TRUE */ void mf_close(mfp, del_file) memfile_T *mfp; int del_file; { bhdr_T *hp, *nextp; NR_TRANS *tp, *tpnext; int i; if (mfp == NULL) /* safety check */ return; if (mfp->mf_fd >= 0) { if (close(mfp->mf_fd) < 0) EMSG(_(e_swapclose)); } if (del_file && mfp->mf_fname != NULL) mch_remove(mfp->mf_fname); /* free entries in used list */ for (hp = mfp->mf_used_first; hp != NULL; hp = nextp) { total_mem_used -= hp->bh_page_count * mfp->mf_page_size; nextp = hp->bh_next; mf_free_bhdr(hp); } while (mfp->mf_free_first != NULL) /* free entries in free list */ vim_free(mf_rem_free(mfp)); for (i = 0; i < MEMHASHSIZE; ++i) /* free entries in trans lists */ for (tp = mfp->mf_trans[i]; tp != NULL; tp = tpnext) { tpnext = tp->nt_next; vim_free(tp); } vim_free(mfp->mf_fname); vim_free(mfp->mf_ffname); vim_free(mfp); } /* * Close the swap file for a memfile. Used when 'swapfile' is reset. */ void mf_close_file(buf, getlines) buf_T *buf; int getlines; /* get all lines into memory? */ { memfile_T *mfp; linenr_T lnum; mfp = buf->b_ml.ml_mfp; if (mfp == NULL || mfp->mf_fd < 0) /* nothing to close */ return; if (getlines) { /* get all blocks in memory by accessing all lines (clumsy!) */ mf_dont_release = TRUE; for (lnum = 1; lnum <= buf->b_ml.ml_line_count; ++lnum) (void)ml_get_buf(buf, lnum, FALSE); mf_dont_release = FALSE; /* TODO: should check if all blocks are really in core */ } if (close(mfp->mf_fd) < 0) /* close the file */ EMSG(_(e_swapclose)); mfp->mf_fd = -1; if (mfp->mf_fname != NULL) { mch_remove(mfp->mf_fname); /* delete the swap file */ vim_free(mfp->mf_fname); vim_free(mfp->mf_ffname); mfp->mf_fname = NULL; mfp->mf_ffname = NULL; } } /* * Set new size for a memfile. Used when block 0 of a swapfile has been read * and the size it indicates differs from what was guessed. */ void mf_new_page_size(mfp, new_size) memfile_T *mfp; unsigned new_size; { /* Correct the memory used for block 0 to the new size, because it will be * freed with that size later on. */ total_mem_used += new_size - mfp->mf_page_size; mfp->mf_page_size = new_size; } /* * get a new block * * negative: TRUE if negative block number desired (data block) */ bhdr_T * mf_new(mfp, negative, page_count) memfile_T *mfp; int negative; int page_count; { bhdr_T *hp; /* new bhdr_T */ bhdr_T *freep; /* first block in free list */ char_u *p; /* * If we reached the maximum size for the used memory blocks, release one * If a bhdr_T is returned, use it and adjust the page_count if necessary. */ hp = mf_release(mfp, page_count); /* * Decide on the number to use: * If there is a free block, use its number. * Otherwise use mf_block_min for a negative number, mf_block_max for * a positive number. */ freep = mfp->mf_free_first; if (!negative && freep != NULL && freep->bh_page_count >= page_count) { /* * If the block in the free list has more pages, take only the number * of pages needed and allocate a new bhdr_T with data * * If the number of pages matches and mf_release() did not return a * bhdr_T, use the bhdr_T from the free list and allocate the data * * If the number of pages matches and mf_release() returned a bhdr_T, * just use the number and free the bhdr_T from the free list */ if (freep->bh_page_count > page_count) { if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL) return NULL; hp->bh_bnum = freep->bh_bnum; freep->bh_bnum += page_count; freep->bh_page_count -= page_count; } else if (hp == NULL) /* need to allocate memory for this block */ { if ((p = (char_u *)alloc(mfp->mf_page_size * page_count)) == NULL) return NULL; hp = mf_rem_free(mfp); hp->bh_data = p; } else /* use the number, remove entry from free list */ { freep = mf_rem_free(mfp); hp->bh_bnum = freep->bh_bnum; vim_free(freep); } } else /* get a new number */ { if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL) return NULL; if (negative) { hp->bh_bnum = mfp->mf_blocknr_min--; mfp->mf_neg_count++; } else { hp->bh_bnum = mfp->mf_blocknr_max; mfp->mf_blocknr_max += page_count; } } hp->bh_flags = BH_LOCKED | BH_DIRTY; /* new block is always dirty */ mfp->mf_dirty = TRUE; hp->bh_page_count = page_count; mf_ins_used(mfp, hp); mf_ins_hash(mfp, hp); /* * Init the data to all zero, to avoid reading uninitialized data. * This also avoids that the passwd file ends up in the swap file! */ (void)vim_memset((char *)(hp->bh_data), 0, (size_t)mfp->mf_page_size); return hp; } /* * get existing block 'nr' with 'page_count' pages * * Note: The caller should first check a negative nr with mf_trans_del() */ bhdr_T * mf_get(mfp, nr, page_count) memfile_T *mfp; blocknr_T nr; int page_count; { bhdr_T *hp; /* doesn't exist */ if (nr >= mfp->mf_blocknr_max || nr <= mfp->mf_blocknr_min) return NULL; /* * see if it is in the cache */ hp = mf_find_hash(mfp, nr); if (hp == NULL) /* not in the hash list */ { if (nr < 0 || nr >= mfp->mf_infile_count) /* can't be in the file */ return NULL; /* could check here if the block is in the free list */ /* * Check if we need to flush an existing block. * If so, use that block. * If not, allocate a new block. */ hp = mf_release(mfp, page_count); if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL) return NULL; hp->bh_bnum = nr; hp->bh_flags = 0; hp->bh_page_count = page_count; if (mf_read(mfp, hp) == FAIL) /* cannot read the block! */ { mf_free_bhdr(hp); return NULL; } } else { mf_rem_used(mfp, hp); /* remove from list, insert in front below */ mf_rem_hash(mfp, hp); } hp->bh_flags |= BH_LOCKED; mf_ins_used(mfp, hp); /* put in front of used list */ mf_ins_hash(mfp, hp); /* put in front of hash list */ return hp; } /* * release the block *hp * * dirty: Block must be written to file later * infile: Block should be in file (needed for recovery) * * no return value, function cannot fail */ void mf_put(mfp, hp, dirty, infile) memfile_T *mfp; bhdr_T *hp; int dirty; int infile; { int flags;