home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / MEMINTRL.C < prev    next >
C/C++ Source or Header  |  1994-04-17  |  128KB  |  2,547 lines

  1. /**********************************************************************/
  2. /*                                                                    */
  3. /*     Module: MEMINTRL.INC                                           */
  4. /*                                                                    */
  5. /*     This module contains the internal routines used by MEMLIB.C.   */
  6. /*     These functions are designed to be called by the functions     */
  7. /*     contained in MEMLIB.C only and are not for use by an           */
  8. /*     application.                                                   */
  9. /*                                                                    */
  10. /**********************************************************************/
  11.   
  12. /*$PAGE*/
  13. /*====================================================================*/
  14. /*   INCLUDE FILES                                                    */
  15. /*====================================================================*/
  16.   
  17. #include <stddef.h>
  18. #include <malloc.h>
  19. #include <dos.h>
  20.   
  21. /*******************************************************************/
  22. /* Error code definitions for MEMLIB.  Since MEMLIB makes calls to */
  23. /* EMMLIB you may get EMM specific errors.  These errors can be    */
  24. /* found in table A-2 in the EMS manual.                           */
  25. /*******************************************************************/
  26.   
  27. #include "errors.h"
  28.   
  29. /********************************/
  30. /* External Function prototypes */
  31. /********************************/
  32.   
  33. #include "memlib.h"
  34. #include "emmlib.h"
  35.   
  36. /********************************/
  37. /* Internal Function prototypes */
  38. /********************************/
  39.   
  40. unsigned int init_exp_mem   (void);
  41. unsigned int break_overlap  (unsigned int *);
  42. unsigned int check_best_fit (unsigned int, unsigned int *, long *);
  43. unsigned int split_block    (unsigned int, unsigned int);
  44. unsigned int search_after   (unsigned int, unsigned int *, unsigned int *);
  45. unsigned int search_before  (unsigned int, unsigned int *, unsigned int *);
  46. unsigned int coalesce_block (unsigned int, unsigned int, unsigned int *);
  47. unsigned int map_dir_page   (unsigned int, unsigned int);
  48. unsigned int check_token    (unsigned int);
  49. unsigned int find_new_dir_start          (void);
  50. unsigned int restore_memlib_context      (unsigned int);
  51. unsigned int allocate_new_directory_page (void);
  52. unsigned int allocate_new_block          (unsigned int, unsigned int);
  53. unsigned int check_if_all_blocks_free    (unsigned int *);
  54. unsigned int prepare_dir_mapping         (unsigned int *);
  55.   
  56. /*$PAGE*/
  57. /*====================================================================*/
  58. /*   DEFINES                                                          */
  59. /*====================================================================*/
  60.   
  61. #define TRUE                       (unsigned int) 1
  62. #define FALSE                      (unsigned int) 0
  63. #define PASSED                     (unsigned int) 0
  64. #define K64K                       (unsigned long) (64L * 1024L)
  65. #define K16K                       (unsigned int) (16 * 1024)
  66.   
  67. #define PAGE_SIZE                  (unsigned int) K16K
  68. #define MAX_PAGE_FRAME_SIZE        (unsigned int) 24
  69. #define LARGEST_ALLOCATABLE_BLOCK  (unsigned int) (K64K - 1)
  70. #define MAX_ALLOCATABLE_PAGES      (unsigned int) 4
  71. #define MAX_CONTEXTS_AVAILABLE     (unsigned int) 10
  72. #define MAX_DIR_ENTRIES            (unsigned int) (K64K - 1)
  73.   
  74. #define FIRST_PHYS_PAGE            (unsigned int) 0
  75. #define SECOND_PHYS_PAGE           (unsigned int) 1
  76.   
  77. #define UNASSIGNED_TOKEN           (unsigned int) 0xFFFF
  78. #define OFFSET_SIZE                (unsigned int) 0x0400
  79. #define UNMAPPED                   (unsigned int) 0xFFFF
  80. #define NO_CONTEXTS                (unsigned int) 0xFFFF
  81.   
  82. #define EMM_NOT_ENOUGH_PAGES       (unsigned int) 0x88
  83.   
  84. #define DIR_ENTRIES_PER_PAGE       (PAGE_SIZE / sizeof(DIRECTORY_NODE))
  85.   
  86. /*$PAGE*/
  87. /*====================================================================*/
  88. /*   TYPEDEFS                                                         */
  89. /*====================================================================*/
  90.   
  91. /**********************************************************************/
  92. /* This structure stores the housekeeping information used to         */
  93. /* uniquely identify a block of memory and to do garbage collection.  */
  94. /* The directory is an array of these structures.                     */
  95. /*                                                                    */
  96. /*  token        - An identifier to a block of memory which is an     */
  97. /*                 index in the directory array.                      */
  98. /*  size         - The size of the memory block.                      */
  99. /*  logical_page - The array of logical pages that the block uses.    */
  100. /*  offset       - The offset into this block's first logical page.   */
  101. /*                 We only need to keep track of the offset since the */
  102. /*                 segment is set by seteptrs when access is desired. */
  103. /*                                                                    */
  104. /* We must keep track of the directory entries in two ways (an entry  */
  105. /* meaning the index into the directory array which gives us access   */
  106. /* to the structure above).  One is in which the token is used as an  */
  107. /* index into the directory array, giving us a range of 0 - 65535     */
  108. /* directory entries.  Second is when we actually want to access a    */
  109. /* directory entry.  Since we cannot map in the entire directory, due */
  110. /* to its size, we must find what logical page an entry belongs to,   */
  111. /* map that page in, and access that entry by using an index into     */
  112. /* that page.  This index has a range of 0 to the number of entries   */
  113. /* possible in a page.                                                */
  114. /*                                                                    */
  115. /* Note: The token has two uses -- one for identifying a block of     */
  116. /* memory and other as an index into the full directory array which   */
  117. /* gives us acces to a DIRECTORY_NODE structure.  The user of MEMLIB  */
  118. /* always keeps track of his blocks of memory with the token value    */
  119. /* and does not have to worry about the directory array.              */
  120. /*                                                                    */
  121. /* In order to know which logical page to map in we use the following */
  122. /* formula:                                                           */
  123. /*                                                                    */
  124. /* directory_log_page = token / DIR_ENTRIES_PER_PAGE                  */
  125. /*                                                                    */
  126. /* Token is the actual entry into the directory that identifies a     */
  127. /* block.  NUM_DIR_ENTRIES is a macro that returns the number of      */
  128. /* directory entries possible in a given number of pages -- in this   */
  129. /* case one page.  By performing an integer divide, we obtain the     */
  130. /* logical page number that this token's directory entry resides in.  */
  131. /*                                                                    */
  132. /* In order to access a directory entry when it is mapped in we use   */
  133. /* this formula:                                                      */
  134. /*                                                                    */
  135. /* directory_index = token % DIR_ENTRIES_PER_PAGE                     */
  136. /*                                                                    */
  137. /* This number is used as an index into the page of the directory     */
  138. /* array that's mapped in.  This number is different than the token   */
  139. /* which identifies the entry into the full directory array.          */
  140. /**********************************************************************/
  141.   
  142. typedef struct
  143. {
  144.     unsigned int token;
  145.     unsigned int size;
  146.     unsigned int logical_page [MAX_ALLOCATABLE_PAGES];
  147.     unsigned int offset;
  148.   
  149. } DIRECTORY_NODE;
  150.   
  151. /**********************************************************************/
  152. /* This structure is for holding the segment and page number of a     */
  153. /* mappable memory region.  This will be used in an array to hold the */
  154. /* entire list of mappable memory regions.                            */
  155. /**********************************************************************/
  156.   
  157. typedef struct
  158. {
  159.     unsigned int phys_page_segment;
  160.     unsigned int phys_page_number;
  161.   
  162. } MAPPABLE_REGIONS;
  163.   
  164.   
  165. /*$PAGE*/
  166. /*====================================================================*/
  167. /*                 MACROS                                             */
  168. /*====================================================================*/
  169.   
  170. /**********************************************************************/
  171. /* This macro returns the number of PAGE_SIZE pages needed for a      */
  172. /* memory block of the given size.                                    */
  173. /**********************************************************************/
  174. #define NUM_PAGES(size) ((unsigned int) (((unsigned long) size + PAGE_SIZE - 1) / PAGE_SIZE))
  175.   
  176. /**********************************************************************/
  177. /* This macro returns the number of directory entries that fit within */
  178. /* the given amount of PAGES_SIZE pages.                              */
  179. /**********************************************************************/
  180. #define NUM_DIR_ENTRIES(num_pages) ((unsigned long) (PAGE_SIZE / sizeof (DIRECTORY_NODE)) * num_pages)
  181.   
  182. /*$PAGE*/
  183. /*====================================================================*/
  184. /*   GLOBAL VARIABLES                                                 */
  185. /*====================================================================*/
  186.   
  187. /**********************************************************************/
  188. /* Actual number of PAGE_SIZE pages available in the page frame       */
  189. /**********************************************************************/
  190.   
  191. unsigned int num_pages_in_page_frame;
  192.   
  193. /**********************************************************************/
  194. /* Store the page frame base address                                  */
  195. /**********************************************************************/
  196.   
  197. void far* page_frame_base_address;
  198.   
  199. /**********************************************************************/
  200. /* Store the EMM handle that the app will use                         */
  201. /* Store the EMM handle that the memory manager will use              */
  202. /**********************************************************************/
  203.   
  204. unsigned int app_handle;
  205. unsigned int man_handle;
  206.   
  207. /**********************************************************************/
  208. /* The first time that any of the external MEMLIB functions are       */
  209. /* called the initializing routine must be called.  This flag is set  */
  210. /* to TRUE once the call is made.                                     */
  211. /**********************************************************************/
  212.   
  213. unsigned int exp_initialized = FALSE;
  214.   
  215. /**********************************************************************/
  216. /* An array of pointers to each pysical page that the directory uses. */
  217. /* When we need to access two different entries on two separate pages */
  218. /* we can map both pages needed in.                                   */
  219. /**********************************************************************/
  220.   
  221. DIRECTORY_NODE far* directory[2];
  222.   
  223. /**********************************************************************/
  224. /* Number of pages for the directory (dynamically changes)            */
  225. /**********************************************************************/
  226.   
  227. unsigned int dir_page_count;
  228.   
  229. /**********************************************************************/
  230. /* Array tells which logical page is mapped at each physical page.    */
  231. /* UNMAPPED ==> no page is mapped.   Unmap 24 pages (A000 - EFFF).    */
  232. /**********************************************************************/
  233.   
  234. MAP_STRUCT pages_mapped[MAX_PAGE_FRAME_SIZE] =
  235. {
  236.     UNMAPPED,0,  UNMAPPED,1,  UNMAPPED,2,  UNMAPPED,3,
  237.     UNMAPPED,4,  UNMAPPED,5,  UNMAPPED,6,  UNMAPPED,7,
  238.     UNMAPPED,8,  UNMAPPED,9,  UNMAPPED,10, UNMAPPED,11,
  239.     UNMAPPED,12, UNMAPPED,13, UNMAPPED,14, UNMAPPED,15,
  240.     UNMAPPED,16, UNMAPPED,17, UNMAPPED,18, UNMAPPED,19,
  241.     UNMAPPED,20, UNMAPPED,21, UNMAPPED,22, UNMAPPED,23
  242. };
  243.   
  244. /**********************************************************************/
  245. /* number_pages_mapped stores the number actually mapped.             */
  246. /**********************************************************************/
  247.   
  248. unsigned int number_pages_mapped = 0;
  249.   
  250. /**********************************************************************/
  251. /* The total number of pages allocated to the application.            */
  252. /**********************************************************************/
  253.   
  254. unsigned int total_app_allocated_pages;
  255.   
  256. /**********************************************************************/
  257. /* Used to get and restore partial page maps for push_context() and   */
  258. /* pop_context().                                                     */
  259. /**********************************************************************/
  260.   
  261. PARTIAL_CONTEXT_LIST_STRUCT partial_page_map;
  262.   
  263. /**********************************************************************/
  264. /* An array of pointers to saved contexts used by the push_context()  */
  265. /* and pop_context() functions.                                       */
  266. /**********************************************************************/
  267.   
  268. CONTEXT_STRUCT* context_ptrs[MAX_CONTEXTS_AVAILABLE];
  269.   
  270. /**********************************************************************/
  271. /* This variable keeps track of the top of the context_ptrs array.    */
  272. /* This allows pop_context() to know whether there are any contexts   */
  273. /* left to remove or for push_context() to know whether there is      */
  274. /* enough room to store another context.                              */
  275. /**********************************************************************/
  276.   
  277. unsigned int context_top;
  278.   
  279. /**********************************************************************/
  280. /* Size of each context - set in init_exp_mem().                      */
  281. /**********************************************************************/
  282.   
  283. unsigned int context_size;
  284.   
  285. /**********************************************************************/
  286. /* The index into the full directory array used as the starting       */
  287. /* location when searching through the directory for a viable entry   */
  288. /* to keep track of a new memory block.                               */
  289. /**********************************************************************/
  290.   
  291. unsigned int dir_start;
  292.   
  293. /**********************************************************************/
  294. /* The index into the full directory array used as the ending         */
  295. /* location when searching through the directory for a viable entry   */
  296. /* to keep track of a new memory block.                               */
  297. /**********************************************************************/
  298.   
  299. unsigned int dir_end;
  300.   
  301. /*$PAGE*/
  302. /*====================================================================*/
  303. /*              CODE                                                  */
  304. /*====================================================================*/
  305.   
  306. /**********************************************************************/
  307. /*     Name:  unsigned int prepare_dir_mapping (context_saved)        */
  308. /*            unsigned int *context_saved;                            */
  309. /*                                                                    */
  310. /*     Definition:                                                    */
  311. /*        To save the context before mapping in the directory.  This  */
  312. /*     function is called before a directory page will be mapped in.  */
  313. /*     It firsts checks to see if the expanded memory has been        */
  314. /*     initialized and then saves the current context.  The status    */
  315. /*     will be returned to the caller for error checking.             */
  316. /*     'context_saved' is set to TRUE if save_context() was           */
  317. /*     successful.                                                    */
  318. /*                                                                    */
  319. /*     The calling function can then call restore_memlib_context()    */
  320. /*     depending whether 'saved' is TRUE or not.  This allows the     */
  321. /*     caller to preserve the error status from save_context().       */
  322. /*                                                                    */
  323. /*     Parameters:                                                    */
  324. /*        output  context_saved  Whether the context was saved or not */
  325. /*                                                                    */
  326. /*     Results returned:                                              */
  327. /*        PASSED     Operation successful                             */
  328. /*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
  329. /*                                                                    */
  330. /*     Calls: init_exp_mem()                                          */
  331. /*            save_context()                                          */
  332. /*                                                                    */
  333. /*     Called by: ememavl()                                           */
  334. /*                ememmax()                                           */
  335. /*                emsize()                                            */
  336. /*                efmalloc()                                          */
  337. /*                effree()                                            */
  338. /*                                                                    */
  339. /*     Globals referenced/modified: exp_initialized                   */
  340. /*                                  man_handle                        */
  341. /*                                                                    */
  342. /**********************************************************************/
  343.   
  344. unsigned int prepare_dir_mapping (context_saved)
  345. unsigned int *context_saved;
  346. {
  347.     unsigned int status;          /* The status of EMM and MEMLIB */
  348.   
  349.     *context_saved = FALSE;
  350.     status         = PASSED;
  351.   
  352.    /**********************************************/
  353.    /* If expanded memory hasn't been initialized */
  354.    /* then call init_exp_mem().                  */
  355.    /**********************************************/
  356.   
  357.     if (!exp_initialized)
  358.         status = init_exp_mem();
  359.   
  360.     if (status == PASSED)
  361.     {
  362.       /*****************************/
  363.       /* Save the current context. */
  364.       /*****************************/
  365.   
  366.         status = save_context (man_handle);
  367.         if (status == PASSED)
  368.         {
  369.             *context_saved = TRUE;
  370.         }
  371.     }
  372.     return (status);
  373.   
  374. } /** prepare_dir_mapping **/
  375.   
  376. /*$PAGE*/
  377. /**********************************************************************/
  378. /*     Name:  unsigned int map_dir_page (log_page, phys_page)         */
  379. /*            unsigned int log_page;                                  */
  380. /*            unsigned int phys_page;                                 */
  381. /*                                                                    */
  382. /*     Definition:                                                    */
  383. /*        Maps in the specified logical page for the directory into   */
  384. /*     the specified physical page.  For use by MEMLIB only (uses     */
  385. /*     MEMLIB handle -- man_handle).                                  */
  386. /*                                                                    */
  387. /*     Parameters:                                                    */
  388. /*        input   log_page    The logical directory page to map in    */
  389. /*        input   phys_page   Which physical page to map log_page in  */
  390. /*                                                                    */
  391. /*     Results returned:                                              */
  392. /*        PASSED     Operation successful                             */
  393. /*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
  394. /*                                                                    */
  395. /*     Calls: map_unmap_pages()                                       */
  396. /*                                                                    */
  397. /*     Called by: ememavl()                                           */
  398. /*                ememmax()                                           */
  399. /*                emsize()                                            */
  400. /*                efmalloc()                                          */
  401. /*                effree()                                            */
  402. /*                seteptrs()                                          */
  403. /*                                                                    */
  404. /*     Globals referenced/modified: exp_intialized                    */
  405. /*                                  man_handle                        */
  406. /*                                                                    */
  407. /**********************************************************************/
  408.   
  409. unsigned int map_dir_page (log_page, phys_page)
  410. unsigned int log_page;
  411. unsigned int phys_page;
  412. {
  413.     MAP_STRUCT   directory_map[1];  /* Structure to use EMS map pages */
  414.     unsigned int status;            /* Status of EMM and MEMLIB       */
  415.   
  416.     directory_map[0].log_page         = log_page;
  417.     directory_map[0].phys_page_or_seg = phys_page;
  418.     status = map_unmap_pages (PHYS_PAGE_MODE, 1, directory_map, man_handle);
  419.   
  420.     return (status);
  421. } /** end map_dir_page **/
  422.   
  423. /*$PAGE*/
  424. /**********************************************************************/
  425. /*                                                                    */
  426. /*     Name:    unsigned int restore_memlib_context (status)          */
  427. /*              unsigned int status;                                  */
  428. /*                                                                    */
  429. /*     Description:                                                   */
  430. /*        Restores a context saved by prepare_dir_mapping() so that   */
  431. /*     memlib can access the directory.  If the status passed in is   */
  432. /*     an error, then that is the status returned regardless if       */
  433. /*     restore_context() generates an error.  If the status passed in */
  434. /*     is PASSED, we return the status generated by restore_context().*/
  435. /*        We do this so that in some recoverable errors we can        */
  436. /*     successfully restore the context and still return the correct  */
  437. /*     error code to the application.                                 */
  438. /*                                                                    */
  439. /*     Parameters:                                                    */
  440. /*        input   status     The status passed in                     */
  441. /*                                                                    */
  442. /*     Results returned:                                              */
  443. /*        PASSED     Operation successful                             */
  444. /*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
  445. /*                                                                    */
  446. /*     Calls: restore_context()                                       */
  447. /*                                                                    */
  448. /*     Called by: ememavl()                                           */
  449. /*                ememmax()                                           */
  450. /*                emsize()                                            */
  451. /*                efmalloc()                                          */
  452. /*                effree()                                            */
  453. /*                                                                    */
  454. /*     Globals referenced/modified: man_handle                        */
  455. /*                                                                    */
  456. /**********************************************************************/
  457.   
  458. unsigned int restore_memlib_context (status)
  459. unsigned int status;
  460. {
  461.     unsigned int restore_status;  /* Status returned from restore_context */
  462.   
  463.     restore_status = restore_context (man_handle);
  464.     if (status == PASSED)
  465.         return (restore_status);
  466.     else
  467.         return (status);
  468.   
  469. } /** end restore_memlib_context **/
  470.   
  471. /*$PAGE*/
  472. /**********************************************************************/
  473. /*                                                                    */
  474. /*     Name:  unsigned int check_token (token)                        */
  475. /*            unsigned int token;                                     */
  476. /*                                                                    */
  477. /*     Description:                                                   */
  478. /*        This function check's a token to see if it is valid.  It    */
  479. /*     is valid if it is within the directory boundries.  A token is  */
  480. /*     valid when it is set by efmalloc().                            */
  481. /*                                                                    */
  482. /*     Parameters:                                                    */
  483. /*        input    token   The token to be validated.                 */
  484. /*                                                                    */
  485. /*     Results returned:                                              */
  486. /*        PASSED     Operation successful                             */
  487. /*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
  488. /*                                                                    */
  489. /*     Calls: None                                                    */
  490. /*                                                                    */
  491. /*     Called by: effree()                                            */
  492. /*                emsize()                                            */
  493. /*                                                                    */
  494. /*     Globals referenced/modified: dir_page_count                    */
  495. /*                                  exp_initialized                   */
  496. /*                                                                    */
  497. /**********************************************************************/
  498.   
  499. unsigned int check_token (token)
  500. unsigned int token;
  501. {
  502.     unsigned int status;          /* The status of EMM and MEMLIB */
  503.   
  504.    /******************/
  505.    /* Assume PASSED. */
  506.    /******************/
  507.   
  508.     status = PASSED;
  509.   
  510.    /****************************************************************/
  511.    /* If the manager is not initialized then the token is invalid. */
  512.    /****************************************************************/
  513.   
  514.     if (!exp_initialized)
  515.         status = INVALID_TOKEN;
  516.   
  517.    /***************************************************************/
  518.    /* First make sure the token isn't greater than the number of  */
  519.    /* entries possible for the current number of directory pages. */
  520.    /* Then check for a valid token.                               */
  521.    /***************************************************************/
  522.   
  523.     if (status == PASSED)
  524.     {
  525.         if ((token > (unsigned int) (NUM_DIR_ENTRIES (dir_page_count) - 1)) ||
  526.             (token == UNASSIGNED_TOKEN))
  527.             status = INVALID_TOKEN;
  528.     }
  529.   
  530.     return(status);
  531.   
  532. } /** end check_token **/
  533.   
  534. /*$PAGE*/
  535. /**********************************************************************/
  536. /*                                                                    */
  537. /*     Name:     unsigned int init_exp_mem (void)                     */
  538. /*                                                                    */
  539. /*     Description:                                                   */
  540. /*        This routine initializes the housekeeping variables needed  */
  541. /*     to keep track of expanded memory.  It tests for the presence   */
  542. /*     of EMM 4.0 and initializes the directory.                      */
  543. /*                                                                    */
  544. /*     Parameters: None                                               */
  545. /*                                                                    */
  546. /*     Results returned:                                              */
  547. /*        PASSED     Operation successful                             */
  548. /*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
  549. /*                                                                    */
  550. /*     Calls: alloc_pages()                                           */
  551. /*            EMM_installed()                                         */
  552. /*            get_page_frame_seg()                                    */
  553. /*            get_partial_context_size()                              */
  554. /*            get_unalloc_page_count()                                */
  555. /*            realloc_pages()                                         */
  556. /*            map_dir_page()                                          */
  557. /*            get_page_frame_count()                                  */
  558. /*                                                                    */
  559. /*     Called by: prepare_dir_mapping()                               */
  560. /*                push_context()                                      */
  561. /*                pop_context()                                       */
  562. /*                                                                    */
  563. /*     Globals referenced/modified: directory                         */
  564. /*                                  app_handle                        */
  565. /*                                  context_size                      */
  566. /*                                  dir_page_count                    */
  567. /*                                  exp_intialized                    */
  568. /*                                  man_handle                        */
  569. /*                                  number_pages_mapped               */
  570. /*                                  page_frame_base_address           */
  571. /*                                  num_pages_in_page_frame           */
  572. /*                                  pages_mapped                      */
  573. /*                                  context_top                       */
  574. /*                                  total_app_allocated_pages         */
  575. /*                                  dir_start                         */
  576. /*                                  dir_end                           */
  577. /*                                  exp_initialized                   */
  578. /*                                  partial_page_map                  */
  579. /*                                                                    */
  580. /**********************************************************************/
  581.   
  582. unsigned int init_exp_mem (void)
  583. {
  584.   
  585.     unsigned int status;            /* The status of EMM and MEMLIB */
  586.     unsigned int num_unalloc_pages; /* Number of unallocated pages  */
  587.     unsigned int page_frame_seg;    /* Page frame segment           */
  588.     unsigned int i;                 /* Looping variable             */
  589.     unsigned int zero_pages;        /* To call realloc for 0 pages  */
  590.   
  591.    /********************************************************/
  592.    /* Test for EMM presence and enough pages -- need at    */
  593.    /* least 1 for the directory and 1 for the application. */
  594.    /********************************************************/
  595.   
  596.     status = EMM_installed();
  597.     if (status == PASSED)
  598.     {
  599.         status = get_unalloc_page_count (&num_unalloc_pages);
  600.         if (status == PASSED)
  601.             if (num_unalloc_pages <= 1)
  602.                 status = NOT_ENOUGH_UNALLOCATED_PAGES;
  603.     }
  604.   
  605.     if (status == PASSED)
  606.     {
  607.       /*****************************************/
  608.       /* Allocate 0 pages for the application. */
  609.       /* We need to first alloc 1 page to get  */
  610.       /* a handle then realloc to reduce the   */
  611.       /* number of pages used to 0.            */
  612.       /*****************************************/
  613.   
  614.         status = alloc_pages (1, &app_handle);
  615.         if (status == PASSED)
  616.         {
  617.             zero_pages = 0;
  618.             status = realloc_pages (&zero_pages, app_handle);
  619.             if ((zero_pages != 0) ||
  620.                 (status == EMM_NOT_ENOUGH_PAGES))
  621.                 status = NOT_ENOUGH_UNALLOCATED_PAGES;
  622.         }
  623.   
  624.       /*********************************************/
  625.       /* Allocate 1 page for the manager (memlib). */
  626.       /*********************************************/
  627.   
  628.         if (status == PASSED)
  629.             status = alloc_pages (1, &man_handle);
  630.   
  631.         if (status == PASSED)
  632.         {
  633.          /****************************/
  634.          /* Map this directory page. */
  635.          /****************************/
  636.   
  637.             status = map_dir_page (0, FIRST_PHYS_PAGE);
  638.         }
  639.   
  640.         if (status == PASSED)
  641.         {
  642.          /*********************************************************/
  643.          /* Get the base address of the start of expanded memory. */
  644.          /*********************************************************/
  645.   
  646.             status = get_page_frame_seg (&page_frame_seg);
  647.             if (status == PASSED)
  648.             {
  649.             /***************************************************/
  650.             /* Convert the page frame segment to a far pointer */
  651.             /* and point directory[0] to it.                   */
  652.             /***************************************************/
  653.   
  654.                 page_frame_base_address = FP (page_frame_seg);
  655.                 directory[0] = (DIRECTORY_NODE far *) page_frame_base_address;
  656.   
  657.             /****************************************************/
  658.             /* Point directory[1] to the address of the second  */
  659.             /* physical page in the page frame.                 */
  660.             /****************************************************/
  661.                 FP_SEG(directory[1]) = page_frame_seg + OFFSET_SIZE;
  662.                 FP_OFF(directory[1]) = 0;
  663.             }
  664.         }
  665.     }
  666.   
  667.     if (status == PASSED)
  668.     {
  669.       /************************************************/
  670.       /* Set the variable that keeps track of the how */
  671.       /* many pages the directory is using to 1.      */
  672.       /************************************************/
  673.   
  674.         dir_page_count = 1;
  675.   
  676.       /**************************************************************/
  677.       /* Initialize all the directory entries so that the token     */
  678.       /* identifiers are set UNASSIGNED_TOKEN (entry is available)  */
  679.       /* and their size to 0.                                       */
  680.       /**************************************************************/
  681.   
  682.         for (i = 0; i < DIR_ENTRIES_PER_PAGE; i++)
  683.         {
  684.             directory[0][i].token = UNASSIGNED_TOKEN;
  685.             directory[0][i].size = 0;
  686.         }
  687.   
  688.       /********************************************************/
  689.       /* Set the starting and ending entries in the directory */
  690.       /* when doing free memory block searches.               */
  691.       /********************************************************/
  692.   
  693.         dir_start = 0;
  694.         dir_end   = 0;
  695.   
  696.       /****************************************************************/
  697.       /* Set the total number of pages the application is using to 0. */
  698.       /****************************************************************/
  699.   
  700.         total_app_allocated_pages = 0;
  701.   
  702.       /**********************************************/
  703.       /* Get the number of pages in the page frame. */
  704.       /**********************************************/
  705.   
  706.         status = get_page_frame_count (&num_pages_in_page_frame);
  707.   
  708.         if (status == PASSED)
  709.         {
  710.          /*************************************************/
  711.          /* Set the partial page map for pushes and pops. */
  712.          /*************************************************/
  713.   
  714.             partial_page_map.mappable_region_count = num_pages_in_page_frame;
  715.             partial_page_map.mappable_region_seg[0] = FP_SEG (page_frame_base_address);
  716.   
  717.          /*************************************************************/
  718.          /* Set the segment value for each 16K page in the page frame */
  719.          /* that push_context() & pop_context() will be storing.      */
  720.          /*************************************************************/
  721.   
  722.             for (i = 1; i < num_pages_in_page_frame; i++)
  723.             {
  724.                 partial_page_map.mappable_region_seg[i] =
  725.                 partial_page_map.mappable_region_seg[i - 1] + OFFSET_SIZE;
  726.             }
  727.   
  728.          /***************************************************/
  729.          /* Set the context push and pop stack to be empty. */
  730.          /***************************************************/
  731.   
  732.             context_top = NO_CONTEXTS;
  733.   
  734.          /************************************************************/
  735.          /* Get the number of bytes needed to save (push) a context. */
  736.          /************************************************************/
  737.   
  738.             status = get_partial_context_size (num_pages_in_page_frame, &context_size);
  739.             if (status == PASSED)
  740.             {
  741.             /********************/
  742.             /* Unmap all pages. */
  743.             /********************/
  744.   
  745.                 for (i = 0; i < num_pages_in_page_frame; i++)
  746.                 {
  747.                     pages_mapped[i].log_page = UNMAPPED;
  748.                 }
  749.             }
  750.             number_pages_mapped = 0;
  751.         }
  752.     }
  753.    /***************************************************************/
  754.    /* If status is good then update the already-initialized flag. */
  755.    /***************************************************************/
  756.   
  757.     if (status == PASSED)
  758.         exp_initialized = TRUE;
  759.   
  760.     return (status);
  761.   
  762. } /** end init_exp_mem **/
  763.   
  764. /*$PAGE*/
  765. /**********************************************************************/
  766. /*                                                                    */
  767. /*     Name: unsigned int allocate_new_directory_page (void)          */
  768. /*                                                                    */
  769. /*     Description:                                                   */
  770. /*        This routine attempts to allocate a new page for the        */
  771. /*     directory.                                                     */
  772. /*                                                                    */
  773. /*     Parameters:  None                                              */
  774. /*                                                                    */
  775. /*     Results returned:                                              */
  776. /*        PASSED    Operation successful                              */
  777. /*        error     Non-zero value, see "ERRORS.H" or EMS table A-2   */
  778. /*                                                                    */
  779. /*     Calls: map_dir_page()                                          */
  780. /*            realloc_pages()                                         */
  781. /*                                                                    */
  782. /*     Called by: allocate_new_block()                                */
  783. /*                check_best_fit()                                    */
  784. /*                                                                    */
  785. /*     Globals referenced/modified: directory                         */
  786. /*                                  dir_page_count                    */
  787. /*                                  man_handle                        */
  788. /*                                                                    */
  789. /**********************************************************************/
  790.   
  791. unsigned int allocate_new_directory_page (void)
  792. {
  793.     unsigned int status;            /* The status of EMM and MEMLIB  */
  794.     unsigned int index;             /* Index into a directory page   */
  795.     unsigned int new_num_dir_pages; /* New number of directory pages */
  796.   
  797.    /*****************************/
  798.    /* Assume status will be ok. */
  799.    /*****************************/
  800.   
  801.     status = PASSED;
  802.   
  803.    /******************************************/
  804.    /* Set the new number of directory pages. */
  805.    /******************************************/
  806.   
  807.     new_num_dir_pages = dir_page_count + 1;
  808.   
  809.    /***************************************************/
  810.    /* Make sure we don't allocate beyond the maximum  */
  811.    /* number of directory entries allowable.          */
  812.    /***************************************************/
  813.   
  814.     if ((unsigned long) NUM_DIR_ENTRIES (new_num_dir_pages) > MAX_DIR_ENTRIES)
  815.         status = TOO_MANY_DIRECTORY_ENTRIES;
  816.   
  817.     if (status == PASSED)
  818.     {
  819.       /************************************************/
  820.       /* Attempt to add a new page for the directory. */
  821.       /************************************************/
  822.   
  823.         status = realloc_pages (&new_num_dir_pages, man_handle);
  824.   
  825.       /******************************************/
  826.       /* Make sure the number of pages returned */
  827.       /* is equal to the number we wanted.      */
  828.       /******************************************/
  829.   
  830.         if ((status == EMM_NOT_ENOUGH_PAGES) ||
  831.             (new_num_dir_pages != dir_page_count + 1))
  832.             status = NOT_ENOUGH_UNALLOCATED_PAGES;
  833.   
  834.         if (status == PASSED)
  835.         {
  836.          /************************************************/
  837.          /* Allocate succeeded, update the directory map */
  838.          /************************************************/
  839.   
  840.             dir_page_count++;
  841.   
  842.             status = map_dir_page (dir_page_count - 1, FIRST_PHYS_PAGE);
  843.             if (status == PASSED)
  844.             {
  845.             /*****************************************/
  846.             /* Initialize the new directory entries. */
  847.             /*****************************************/
  848.   
  849.                 for (index = 0; index < DIR_ENTRIES_PER_PAGE; index++)
  850.                 {
  851.                     directory[0][index].token = UNASSIGNED_TOKEN;
  852.                     directory[0][index].size = 0;
  853.                 }
  854.             }
  855.         }
  856.     }
  857.     return (status);
  858.   
  859. }  /** end allocate_new_directory_page **/
  860.   
  861. /*$PAGE*/
  862. /**********************************************************************/
  863. /*                                                                    */
  864. /*     Name: unsigned int allocate_new_block (size, token)            */
  865. /*           unsigned int size;                                       */
  866. /*           unsigned int token;                                      */
  867. /*                                                                    */
  868. /*     Description:                                                   */
  869. /*        This routine attempts to allocate a block of size 'size',   */
  870. /*     in bytes, and set the fields in directory[token] appropriately.*/
  871. /*                                                                    */
  872. /*     Parameters:                                                    */
  873. /*        input size     the size, in bytes, to allocate              */
  874. /*        input token    index into directory for this block          */
  875. /*                                                                    */
  876. /*     Results returned:                                              */
  877. /*        PASSED    Operation successful                              */
  878. /*        error     Non-zero value, see "ERRORS.H" or EMS table A-2   */
  879. /*                                                                    */
  880. /*     Calls: allocate_new_directory_page()                           */
  881. /*            realloc_pages()                                         */
  882. /*            map_dir_page()                                          */
  883. /*                                                                    */
  884. /*     Called by: efmalloc()                                          */
  885. /*                                                                    */
  886. /*     Globals referenced/modified: directory                         */
  887. /*                                  app_handle                        */
  888. /*                                  dir_page_count                    */
  889. /*                                  total_app_allocated_pages         */
  890. /*                                  dir_start                         */
  891. /*                                  dir_end                           */
  892. /*                                                                    */
  893. /**********************************************************************/
  894.   
  895. unsigned int allocate_new_block (size, token)
  896. unsigned int size;
  897. unsigned int token;
  898. {
  899.     unsigned int i;                  /* Looping variable                    */
  900.     unsigned int page;               /* Current directory page mapped in    */
  901.     unsigned int status;             /* Status of EMM and MEMLIB            */
  902.     unsigned int num_pages_needed;   /* Number of pages needed              */
  903.     unsigned int size_mod_page_size; /* Size in bytes MOD PAGE_SIZE         */
  904.     unsigned int new_total_pages;    /* New number of pages for the         */
  905.                                     /* application's handle                */
  906.     unsigned int tokens_page;        /* Token's dir entry's logical page    */
  907.     unsigned int tokens_index;       /* Token's index into its page         */
  908.     unsigned int i_dir_entry;        /* Translate i to an entry into the    */
  909.                                     /* full directory array                */
  910.     unsigned int dir_starts_page;    /* Dir_start's dir entry's log page    */
  911.     unsigned int dir_starts_index;   /* Dir_start's index into its page     */
  912.     unsigned int found_block;        /* Whether a block was found or not    */
  913.     unsigned int remainders_logical_page; /* The remaining portion's first  */
  914.                                          /* logical page                   */
  915.   
  916.     status = PASSED;
  917.   
  918.    /****************************************************************/
  919.    /* Check if we need to allocate another page for the directory. */
  920.    /****************************************************************/
  921.   
  922.     if (dir_end >= (unsigned int) (NUM_DIR_ENTRIES (dir_page_count) - 2))
  923.         status = allocate_new_directory_page();
  924.   
  925.     if (status == PASSED)
  926.     {
  927.       /********************************************/
  928.       /* Allocate enough new pages for this block */
  929.       /********************************************/
  930.   
  931.         num_pages_needed = NUM_PAGES (size);
  932.         new_total_pages = total_app_allocated_pages + num_pages_needed;
  933.   
  934.       /*************************************************************/
  935.       /* Assign the new number of pages to the application handle. */
  936.       /*************************************************************/
  937.   
  938.         status = realloc_pages (&new_total_pages, app_handle);
  939.   
  940.       /******************************************/
  941.       /* Make sure the number of pages returned */
  942.       /* is equal to the number we wanted.      */
  943.       /******************************************/
  944.   
  945.         if ((new_total_pages != (total_app_allocated_pages + num_pages_needed))
  946.             || (status == EMM_NOT_ENOUGH_PAGES))
  947.             status = NOT_ENOUGH_UNALLOCATED_PAGES;
  948.     }
  949.   
  950.    /****************************************************/
  951.    /* If allocate succeeded, set the directory entries */
  952.    /****************************************************/
  953.   
  954.     if (status == PASSED)
  955.     {
  956.       /*******************************************************/
  957.       /* Convert 'token' to its respective directory entry's */
  958.       /* logical page and its index into that page.          */
  959.       /*******************************************************/
  960.   
  961.         tokens_page  = token / DIR_ENTRIES_PER_PAGE;
  962.         tokens_index = token % DIR_ENTRIES_PER_PAGE;
  963.   
  964.       /**************************************/
  965.       /* Map in the token's directory page. */
  966.       /**************************************/
  967.   
  968.         status = map_dir_page (tokens_page, FIRST_PHYS_PAGE);
  969.         if (status == PASSED)
  970.         {
  971.          /**************************************/
  972.          /* Set the entry in the directory for */
  973.          /* the newly allocated block.         */
  974.          /**************************************/
  975.   
  976.             directory[0][tokens_index].token  = token;
  977.             directory[0][tokens_index].size   = size;
  978.             directory[0][tokens_index].offset = 0;
  979.   
  980.          /*********************************************/
  981.          /* Set the logical pages for this block to   */
  982.          /* the logical pages that we just allocated. */
  983.          /*********************************************/
  984.   
  985.             for (i = 0; i < num_pages_needed; i++)
  986.             {
  987.                 directory[0][tokens_index].logical_page[i] =
  988.                 total_app_allocated_pages + i;
  989.             }
  990.   
  991.          /**************************************************/
  992.          /* If this block size is NOT a multiple of 16K,   */
  993.          /* find an unused directory entry and have it     */
  994.          /* point to the remaining part of the page.       */
  995.          /**************************************************/
  996.   
  997.             size_mod_page_size = size % PAGE_SIZE;
  998.   
  999.             if (size_mod_page_size != 0)
  1000.             {
  1001.             /********************************************************/
  1002.             /* We have a remainder on the last logical page for the */
  1003.             /* new block.  Keep track of this page so that when we  */
  1004.             /* set a free directory entry to point to the remainder */
  1005.             /* we already know what logical page it uses.           */
  1006.             /********************************************************/
  1007.   
  1008.                 remainders_logical_page =
  1009.                 directory[0][tokens_index].logical_page[num_pages_needed - 1];
  1010.   
  1011.                 dir_starts_page  = dir_start / DIR_ENTRIES_PER_PAGE;
  1012.                 dir_starts_index = dir_start % DIR_ENTRIES_PER_PAGE;
  1013.                 found_block = FALSE;
  1014.   
  1015.             /****************************************/
  1016.             /* Go through the directory, page by    */
  1017.             /* page, until we find an usable entry. */
  1018.             /****************************************/
  1019.   
  1020.                 for (page = dir_starts_page; ((status == PASSED) &&
  1021.                     (page < dir_page_count) &&
  1022.                     (!found_block)); page++)
  1023.                 {
  1024.                /***********************************/
  1025.                /* Map in the this directory page. */
  1026.                /***********************************/
  1027.   
  1028.                     status = map_dir_page (page, FIRST_PHYS_PAGE);
  1029.   
  1030.                /*********************************************************/
  1031.                /* Go through each entry for the mapped in page until we */
  1032.                /* find a usable entry or until we run out of entries.   */
  1033.                /*********************************************************/
  1034.   
  1035.                     for (i = dir_starts_index; ((i < DIR_ENTRIES_PER_PAGE) &&
  1036.                         (!found_block) &&
  1037.                         (status == PASSED)); i++)
  1038.                     {
  1039.                         if ((directory[0][i].token == UNASSIGNED_TOKEN) &&
  1040.                             (directory[0][i].size == 0))
  1041.                         {
  1042.                      /*******************************************/
  1043.                      /* We found an unused directory entry, set */
  1044.                      /* it to point to the leftover piece.      */
  1045.                      /*******************************************/
  1046.   
  1047.                             directory[0][i].offset = size_mod_page_size;
  1048.                             directory[0][i].size = PAGE_SIZE - size_mod_page_size;
  1049.                             directory[0][i].logical_page[0] = remainders_logical_page;
  1050.   
  1051.                             i_dir_entry = page * DIR_ENTRIES_PER_PAGE + i;
  1052.                             if (i_dir_entry >= dir_end)
  1053.                                 dir_end = i_dir_entry + 1;
  1054.   
  1055.                             found_block = TRUE;
  1056.                         }
  1057.                     } /** end for i **/
  1058.   
  1059.                     dir_starts_index = 0;
  1060.   
  1061.                 } /** end for page **/
  1062.   
  1063.             } /** end if page_mod_page_size **/
  1064.   
  1065.          /***********************************/
  1066.          /* Update the toal allocated pages */
  1067.          /***********************************/
  1068.   
  1069.             total_app_allocated_pages += num_pages_needed;
  1070.   
  1071.         }  /** end if status PASSED **/
  1072.   
  1073.     } /** end if status PASSED **/
  1074.     return (status);
  1075.   
  1076. }  /** end allocate_new_block **/
  1077.   
  1078.   
  1079. /*$PAGE*/
  1080. /**********************************************************************/
  1081. /*                                                                    */
  1082. /*     Name: unsigned int split_block (best_index, size)              */
  1083. /*           unsigned int best_index;                                 */
  1084. /*           unsigned int size;                                       */
  1085. /*                                                                    */
  1086. /*     Description:                                                   */
  1087. /*        This routine splits a block into allocated and unallocated  */
  1088. /*     portions.  The size is assigned to the allocated portion and   */
  1089. /*     the left over portion is set up as a free block.               */
  1090. /*                                                                    */
  1091. /*     Parms Passed:                                                  */
  1092. /*        input best_index   The directory entry to be broken up.     */
  1093. /*                           It will be the entry that will point to  */
  1094. /*                           the allocated portion after it is broken */
  1095. /*                           into its allocated/free portions.        */
  1096. /*              size         The size of the block to be allocated.   */
  1097. /*                                                                    */
  1098. /*     Results returned:                                              */
  1099. /*        PASSED    Operation successful                              */
  1100. /*        error     Non-zero value, see "ERRORS.H" or EMS table A-2   */
  1101. /*                                                                    */
  1102. /*     Calls: map_dir_page()                                          */
  1103. /*            break_overlap()                                         */
  1104. /*                                                                    */
  1105. /*     Called by:  efmalloc()                                         */
  1106. /*                                                                    */
  1107. /*     Globals referenced/modified: directory                         */
  1108. /*                                  dir_page_count                    */
  1109. /*                                  dir_end                           */
  1110. /*                                  dir_start                         */
  1111. /*                                                                    */
  1112. /**********************************************************************/
  1113.   
  1114. unsigned int split_block (best_index, size)
  1115. unsigned int best_index;
  1116. unsigned int size;
  1117. {
  1118.     unsigned int num_pages_for_size; /* The num of logical pages for size  */
  1119.     unsigned int size_mod_page_size; /* The size modulo the PAGE_SIZE      */
  1120.     unsigned int dir_starts_page;    /* Dir_start's dir entry's log page   */
  1121.     unsigned int best_indexs_page;   /* Best_index's dir entry's log page  */
  1122.     unsigned int best_indexs_index;  /* Best_index's index into its page   */
  1123.     unsigned int best_index_offset;  /* Best_index's logical page offset   */
  1124.     unsigned int best_index_size;    /* Best_index's memory block's size   */
  1125.     unsigned int index;              /* Current index into a logical page  */
  1126.     unsigned int page;               /* Current directory page mapped in   */
  1127.     unsigned int remainder;          /* The index into a dir page that     */
  1128.                                     /* will point to the leftover portion */
  1129.                                     /* in a logical page after allocated  */
  1130.                                     /* block is set                       */
  1131.     unsigned int remainders_entry;   /* Remainder converted to a full      */
  1132.                                     /* directory entry                    */
  1133.     unsigned int status;             /* Status of EMM and MEMLIB           */
  1134.     unsigned int j;                  /* Looping variable                   */
  1135.     unsigned int avail_entry_found;  /* An available entry has been found  */
  1136.     unsigned int start_page_for_remainder; /* The starting logical page    */
  1137.                                           /* for the remainder            */
  1138.   
  1139.    /*******************************/
  1140.    /* Initialize local variables. */
  1141.    /*******************************/
  1142.   
  1143.     avail_entry_found = FALSE;
  1144.     status            = PASSED;
  1145.   
  1146.    /*************************************************/
  1147.    /* Convert dir_start to its respective directory */
  1148.    /* entry's logcal page.                          */
  1149.    /*************************************************/
  1150.   
  1151.     dir_starts_page  = dir_start / DIR_ENTRIES_PER_PAGE;
  1152.   
  1153.    /**************************************************/
  1154.    /* Convert dir_start to its respective entry's    */
  1155.    /* page index.  We want to start the first        */
  1156.    /* page's index at the current starting location. */
  1157.    /**************************************************/
  1158.   
  1159.     index = dir_start % DIR_ENTRIES_PER_PAGE;
  1160.   
  1161.    /****************************************************************/
  1162.    /* Check if we need to allocate another page for the directory. */
  1163.    /****************************************************************/
  1164.   
  1165.     if (dir_end >= (unsigned int) (NUM_DIR_ENTRIES (dir_page_count) - 2))
  1166.         status = allocate_new_directory_page();
  1167.   
  1168.    /****************************************************************/
  1169.    /* Go through all the directory pages starting with dir_start's */
  1170.    /* page until we find an usable entry.                          */
  1171.    /****************************************************************/
  1172.   
  1173.     for (page = dir_starts_page; ((page < dir_page_count) &&
  1174.         (!avail_entry_found) &&
  1175.         (status == PASSED)); page++)
  1176.     {
  1177.       /*******************************/
  1178.       /* Map in this directory page. */
  1179.       /*******************************/
  1180.   
  1181.         status = map_dir_page (page, FIRST_PHYS_PAGE);
  1182.       /************************************************************/
  1183.       /* Go through this page's indexes looking for the first     */
  1184.       /* available directory entry to keep track of the remainder */
  1185.       /* portion.  The first time we enter this loop we start     */
  1186.       /* with the current starting location (dir_start converted  */
  1187.       /* to a page's index) from above.  All other index's after  */
  1188.       /* the first page will start with 0.                        */
  1189.       /************************************************************/
  1190.   
  1191.         for (remainder = index; ((remainder < DIR_ENTRIES_PER_PAGE) &&
  1192.             (!avail_entry_found) &&
  1193.             (status == PASSED)); remainder++)
  1194.         {
  1195.             if ((directory[0][remainder].size == 0) &&
  1196.                 (directory[0][remainder].token == UNASSIGNED_TOKEN))
  1197.             {
  1198.             /**********************************************/
  1199.             /* We've found an available directory entry   */
  1200.             /* to keep track of the left-over portion.    */
  1201.             /* Time to map in the block we want to split. */
  1202.             /**********************************************/
  1203.   
  1204.                 avail_entry_found = TRUE;
  1205.   
  1206.             /*******************************************************/
  1207.             /* We're going to map in two different directory pages */
  1208.             /* so that we can reference best_index's and           */
  1209.             /* remainder's directory entry at once.  Since we are  */
  1210.             /* using two different logical pages we need to use    */
  1211.             /* directory[1] to access the second page's entries.   */
  1212.             /*******************************************************/
  1213.   
  1214.                 best_indexs_page  = best_index / DIR_ENTRIES_PER_PAGE;
  1215.                 best_indexs_index = best_index % DIR_ENTRIES_PER_PAGE;
  1216.   
  1217.             /************************************************/
  1218.             /* Map in the best_index's directory page in at */
  1219.             /* physical page one while keeping  remainder's */
  1220.             /* directory page at physical page zero.        */
  1221.             /************************************************/
  1222.   
  1223.                 status = map_dir_page (best_indexs_page, SECOND_PHYS_PAGE);
  1224.                 if (status == PASSED)
  1225.                 {
  1226.                /*****************************/
  1227.                /* Set some local variables. */
  1228.                /*****************************/
  1229.   
  1230.                     best_index_offset  = directory[1][best_indexs_index].offset;
  1231.                     best_index_size    = directory[1][best_indexs_index].size;
  1232.                     num_pages_for_size = NUM_PAGES (size);
  1233.   
  1234.                /*************************************************/
  1235.                /* Split this block into used and free portions. */
  1236.                /*************************************************/
  1237.   
  1238.                     directory[0][remainder].size = best_index_size - size;
  1239.   
  1240.                /***********************************************************/
  1241.                /* Find the starting logical page for the remainder block. */
  1242.                /***********************************************************/
  1243.   
  1244.                     if (((best_index_offset + size) % (PAGE_SIZE)) == 0)
  1245.                         start_page_for_remainder = num_pages_for_size;
  1246.                     else
  1247.                         start_page_for_remainder = num_pages_for_size - 1;
  1248.   
  1249.                /********************************************************/
  1250.                /* Set the logical pages for the newly allocated block. */
  1251.                /********************************************************/
  1252.   
  1253.                     for (j = start_page_for_remainder;
  1254.                         (j < NUM_PAGES (best_index_size)); j++)
  1255.                     {
  1256.                         directory[0][remainder].
  1257.                         logical_page[j - start_page_for_remainder] =
  1258.                         directory[1][best_indexs_index].logical_page[j];
  1259.                     }
  1260.   
  1261.                /*************************************************************/
  1262.                /* Set remainder's index to point to the new leftover piece. */
  1263.                /*************************************************************/
  1264.   
  1265.                     directory[0][remainder].offset =
  1266.                     (best_index_offset + size) % PAGE_SIZE;
  1267.   
  1268.                /*******************/
  1269.                /* Update dir_end. */
  1270.                /*******************/
  1271.   
  1272.                     remainders_entry = remainder + page * DIR_ENTRIES_PER_PAGE;
  1273.                     if (remainders_entry >= dir_end)
  1274.                         dir_end = remainders_entry + 1;
  1275.   
  1276.                /********************************************************/
  1277.                /* If the leftover piece takes more logical pages than  */
  1278.                /* it should (1 page / PAGE_SIZE) then we need to break */
  1279.                /* the remainder piece into two free blocks.            */
  1280.                /********************************************************/
  1281.   
  1282.                     size_mod_page_size = directory[0][remainder].size % PAGE_SIZE;
  1283.                     if (size_mod_page_size >
  1284.                         PAGE_SIZE - directory[0][remainder].offset)
  1285.                         status = break_overlap (&remainders_entry);
  1286.   
  1287.                 } /** if status PASSED **/
  1288.   
  1289.             } /** end if directory **/
  1290.   
  1291.         } /** end for remainder = dir_start **/
  1292.   
  1293.         index = 0;
  1294.   
  1295.     } /** end for page **/
  1296.   
  1297.     return (status);
  1298.   
  1299. } /** end split_block() **/
  1300.   
  1301.   
  1302. /*$PAGE*/
  1303. /**********************************************************************/
  1304. /*                                                                    */
  1305. /*     Name:    unsigned int find_new_dir_start (void)                */
  1306. /*                                                                    */
  1307. /*     Description:                                                   */
  1308. /*        This function finds a new starting location in the          */
  1309. /*     directory.  This starting entry is used when looking for a     */
  1310. /*     new block of memory.                                           */
  1311. /*                                                                    */
  1312. /*     Note: We know the new starting location will always start      */
  1313. /*     after the present one except when we free a block.  In this    */
  1314. /*     case, if the freed block's directory entry is before the       */
  1315. /*     current starting entry, we set the starting location to that   */
  1316. /*     of the newly freed block's directory entry.  This is done in   */
  1317. /*     effree().                                                      */
  1318. /*                                                                    */
  1319. /*     Parameters: None                                               */
  1320. /*                                                                    */
  1321. /*     Results returned:                                              */
  1322. /*        PASSED     Operation successful                             */
  1323. /*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
  1324. /*                                                                    */
  1325. /*     Calls: map_dir_page()                                          */
  1326. /*                                                                    */
  1327. /*     Called by:  check_best_fit()                                   */
  1328. /*                                                                    */
  1329. /*     Globals referenced/modified: directory                         */
  1330. /*                                  directory_map                     */
  1331. /*                                  dir_page_count                    */
  1332. /*                                  dir_start                         */
  1333. /*                                  dir_end                           */
  1334. /*                                                                    */
  1335. /**********************************************************************/
  1336.   
  1337. unsigned int find_new_dir_start()
  1338. {
  1339.     unsigned int i;                 /* Looping variable                  */
  1340.     unsigned int avail_entry_found; /* An available entry has been found */
  1341.     unsigned int dir_starts_page;   /* Dir_start's dir entry's log page  */
  1342.     unsigned int index;             /* The current index into a page     */
  1343.     unsigned int page;              /* The current dir page mapped in    */
  1344.     unsigned int status;            /* Status of EMM and MEMLIB          */
  1345.   
  1346.    /*******************************/
  1347.    /* Initialize local variables. */
  1348.    /*******************************/
  1349.   
  1350.     avail_entry_found  = FALSE;
  1351.     status = PASSED;
  1352.   
  1353.    /***********************************************************/
  1354.    /* Convert dir_start + 1 to its respective directory page. */
  1355.    /***********************************************************/
  1356.   
  1357.     dir_starts_page = (dir_start + 1) / DIR_ENTRIES_PER_PAGE;
  1358.   
  1359.    /***************************************************************/
  1360.    /* Convert dir_start + 1 to its respective entry's page index. */
  1361.    /* We want to start the first page's index from one after the  */
  1362.    /* current starting location.                                  */
  1363.    /***************************************************************/
  1364.   
  1365.     index = (dir_start + 1) % DIR_ENTRIES_PER_PAGE;
  1366.   
  1367.    /****************************************************************/
  1368.    /* Go through all the directory pages starting with dir_start's */
  1369.    /* page until we find an usable entry.                          */
  1370.    /****************************************************************/
  1371.   
  1372.     for (page = dir_starts_page; ((page < dir_page_count) &&
  1373.         (!avail_entry_found) &&
  1374.         (status == PASSED)); page++)
  1375.     {
  1376.       /************************************************/
  1377.       /* Map in the directory page specified by page. */
  1378.       /************************************************/
  1379.   
  1380.         status = map_dir_page (page, FIRST_PHYS_PAGE);
  1381.         if (status == PASSED)
  1382.         {
  1383.          /*****************************************************************/
  1384.          /* Go through this page's entries looking for to first available */
  1385.          /* entry.  The first time we enter this loop we start with the   */
  1386.          /* current starting location + 1 (converted to a page's index)   */
  1387.          /* from above.  All other index's after the first page will      */
  1388.          /* start with 0.                                                 */
  1389.          /*****************************************************************/
  1390.   
  1391.             for (i = index; ((i < DIR_ENTRIES_PER_PAGE) &&
  1392.                 (!avail_entry_found)); i++)
  1393.             {
  1394.                 if (directory[0][i].token == UNASSIGNED_TOKEN)
  1395.                 {
  1396.                /*****************************************/
  1397.                /* Translate the i index into an entry   */
  1398.                /* into the full directory array for the */
  1399.                /* new starting location for dir_start.  */
  1400.                /*****************************************/
  1401.   
  1402.                     dir_start = i + page * DIR_ENTRIES_PER_PAGE;
  1403.   
  1404.                /***************************************/
  1405.                /* Make sure the new starting location */
  1406.                /* isn't greater than the end.  If so, */
  1407.                /* than reset dir_end.                 */
  1408.                /***************************************/
  1409.   
  1410.                     if (dir_start > dir_end)
  1411.                         dir_end = dir_start + 1;
  1412.                     avail_entry_found = TRUE;
  1413.                 }
  1414.             } /** end for i **/
  1415.   
  1416.         } /** end if status PASSED **/
  1417.   
  1418.         index = 0;
  1419.   
  1420.     } /** end for page **/
  1421.   
  1422.     return (status);
  1423.   
  1424. } /** end find_new_dir_start() **/
  1425.   
  1426. /*$PAGE*/
  1427. /**********************************************************************/
  1428. /*                                                                    */
  1429. /*     Name:    unsigned int break_overlap (best_index)               */
  1430. /*              unsigned int *best_index;                             */
  1431. /*                                                                    */
  1432. /*     Description:                                                   */
  1433. /*        This function breaks a free block into two parts at a page  */
  1434. /*     boundry.  This is done because check_best_fit() determined     */
  1435. /*     that the requested block would overlap a page boundry          */
  1436. /*     unnecessarily.  For example, we don't want an 8K block using   */
  1437. /*     two logical pages (part of it on one page and the rest on      */
  1438. /*     another).  Suppose we want to allocate a 9K block and          */
  1439. /*     check_best_fit() determined that a 22K block (6K on one page,  */
  1440. /*     16K on the another) was the best fit.  We want to start the 9K */
  1441. /*     block on a page boundry so that it will fit in one logical     */
  1442. /*     page.  This means that we eventually need to split the 22K     */
  1443. /*     block into three pieces:                                       */
  1444. /*                                                                    */
  1445. /*              6K first free piece on the first logical page.        */
  1446. /*              9K allocated piece on the second logical page.        */
  1447. /*              7K free space on the second logical page.             */
  1448. /*                                                                    */
  1449. /*     This routine will do the first split of 6K and 16K.  The       */
  1450. /*     function split_block(), called from efmalloc(), (which does    */
  1451. /*     all the normal splitting) will split the 16K block into its 9K */
  1452. /*     allocated and 7K free pieces.                                  */
  1453. /*                                                                    */
  1454. /*     Parameters:                                                    */
  1455. /*        output  best_index The directory entry of the best fit loc  */
  1456. /*                                                                    */
  1457. /*     Results returned:                                              */
  1458. /*        PASSED     Operation successful                             */
  1459. /*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
  1460. /*                                                                    */
  1461. /*     Calls: map_dir_page()                                          */
  1462. /*                                                                    */
  1463. /*     Called by:  efmalloc()                                         */
  1464. /*                 split_block()                                      */
  1465. /*                                                                    */
  1466. /*     Globals referenced/modified: dir_page_count                    */
  1467. /*                                  directory                         */
  1468. /*                                  directory_map                     */
  1469. /*                                  dir_end                           */
  1470. /*                                                                    */
  1471. /**********************************************************************/
  1472.   
  1473. unsigned int break_overlap (best_index)
  1474. unsigned int *best_index;
  1475. {
  1476.     unsigned int i;                 /* Looping variable                  */
  1477.     unsigned int entry_found;       /* Whether an entry was found        */
  1478.     unsigned int free_space;        /* The free space before a page      */
  1479.                                    /* boundry in an overlaping block    */
  1480.     unsigned int new_size;          /* The free space starting on a page */
  1481.                                    /* boundry in an overlaping block    */
  1482.     unsigned int status;            /* Status of EMM and MEMLIB          */
  1483.     unsigned int best_indexs_page;  /* Best_index's dir entry's log page */
  1484.     unsigned int best_indexs_index; /* Best_index's index into its page  */
  1485.     unsigned int page;              /* Current directory page mapped in  */
  1486.     unsigned int index;             /* Index into a directory page       */
  1487.     unsigned int j;                 /* Loop variable                     */
  1488.   
  1489.     status = PASSED;
  1490.   
  1491.    /****************************************************************/
  1492.    /* Check if we need to allocate another page for the directory. */
  1493.    /****************************************************************/
  1494.   
  1495.     if (dir_end >= (unsigned int) (NUM_DIR_ENTRIES (dir_page_count) - 2))
  1496.         status = allocate_new_directory_page();
  1497.   
  1498.    /******************************************************************/
  1499.    /* Convert best_index to its respective directory page and index. */
  1500.    /******************************************************************/
  1501.   
  1502.     best_indexs_page  = *best_index / DIR_ENTRIES_PER_PAGE;
  1503.     best_indexs_index = *best_index % DIR_ENTRIES_PER_PAGE;
  1504.   
  1505.    /*******************************************/
  1506.    /* Map in the best_index's directory page. */
  1507.    /*******************************************/
  1508.   
  1509.     status = map_dir_page (best_indexs_page, FIRST_PHYS_PAGE);
  1510.     if (status == PASSED)
  1511.     {
  1512.       /***************************************/
  1513.       /* Set sizes for breaking the overlap. */
  1514.       /***************************************/
  1515.   
  1516.         free_space = PAGE_SIZE - directory[0][best_indexs_index].offset;
  1517.         new_size   = directory[0][best_indexs_index].size - free_space;
  1518.   
  1519.       /**********************************/
  1520.       /* Initialize variables for loop. */
  1521.       /**********************************/
  1522.   
  1523.         entry_found = FALSE;
  1524.         index       = best_indexs_index;
  1525.   
  1526.       /****************************************************/
  1527.       /* Go through all the directory pages starting with */
  1528.       /* best_index's page until we find an usable entry. */
  1529.       /****************************************************/
  1530.   
  1531.         for (page = best_indexs_page; ((page < dir_page_count) &&
  1532.             (!entry_found) &&
  1533.             (status == PASSED)); page++)
  1534.         {
  1535.          /************************************************/
  1536.          /* Map in the directory page specified by page. */
  1537.          /************************************************/
  1538.   
  1539.             status = map_dir_page (page, SECOND_PHYS_PAGE);
  1540.             if (status == PASSED)
  1541.             {
  1542.             /********************************************************/
  1543.             /* Go through this page's entries looking for the first */
  1544.             /* available entry.  The first time we enter this loop  */
  1545.             /* we start with best_index's entry (converted to a     */
  1546.             /* page's index from above).  All other index's after   */
  1547.             /* the first page will start with 0.                    */
  1548.             /********************************************************/
  1549.   
  1550.                 for (i = index; ((i < DIR_ENTRIES_PER_PAGE) &&
  1551.                     (!entry_found) &&
  1552.                     (status == PASSED)); i++)
  1553.                 {
  1554.                     if ((directory[1][i].token == UNASSIGNED_TOKEN) &&
  1555.                         (directory[1][i].size == 0))
  1556.                     {
  1557.                   /********************************************/
  1558.                   /* We found a usable entry.  Convert i to   */
  1559.                   /* a full directory entry for best_index.   */
  1560.                   /* Best_index will now point to this        */
  1561.                   /* directory entry though best_indexs_index */
  1562.                   /* and best_indexs_page will still refer to */
  1563.                   /* the original best_index.  Set this       */
  1564.                   /* directory entry to point to the          */
  1565.                   /* allocated block.                         */
  1566.                   /********************************************/
  1567.   
  1568.                         *best_index            = i + (page * DIR_ENTRIES_PER_PAGE);
  1569.                         directory[1][i].token  = *best_index;
  1570.                         directory[1][i].size   = new_size;
  1571.                         directory[1][i].offset = 0;
  1572.   
  1573.                   /*************************************/
  1574.                   /* Set logical pages for this block. */
  1575.                   /*************************************/
  1576.   
  1577.                         for (j = 0; j < NUM_PAGES (new_size); j++)
  1578.                         {
  1579.                             directory[1][i].logical_page[j] =
  1580.                             directory[0][best_indexs_index].logical_page[j + 1];
  1581.                         }
  1582.   
  1583.                   /***********************************/
  1584.                   /* Update size for original block. */
  1585.                   /***********************************/
  1586.   
  1587.                         directory[0][best_indexs_index].size = free_space;
  1588.   
  1589.                   /*****************************/
  1590.                   /* Update dir_end if needed. */
  1591.                   /*****************************/
  1592.   
  1593.                         if (*best_index >= dir_end)
  1594.                             dir_end = *best_index + 1;
  1595.   
  1596.                         entry_found = TRUE;
  1597.   
  1598.                     } /** end if directory[1][i] **/
  1599.   
  1600.                 } /** end for i **/
  1601.   
  1602.                 index = 0;
  1603.   
  1604.             } /** end if status PASSED **/
  1605.   
  1606.         } /** end for page **/
  1607.   
  1608.     } /** end if status PASSED **/
  1609.   
  1610.     return (status);
  1611.   
  1612. } /** done break_overlap() **/
  1613.   
  1614. /*$PAGE*/
  1615. /**********************************************************************/
  1616. /*                                                                    */
  1617. /*     Name:  unsigned int check_best_fit (size, best_index,          */
  1618. /*                                           min_difference)          */
  1619. /*            unsigned int size;                                      */
  1620. /*            unsigned int *best_index;                               */
  1621. /*            long         *min_difference;                           */
  1622. /*                                                                    */
  1623. /*     Description:                                                   */
  1624. /*        This function finds the best fit for a block of memory      */
  1625. /*     asked for in efmalloc().                                       */
  1626. /*                                                                    */
  1627. /*     Parameters:                                                    */
  1628. /*        input    size           The desired size of the block of    */
  1629. /*                                memory.                             */
  1630. /*        output   best_index     The directory entry of the best fit */
  1631. /*        output   min_difference The remainder from best_fit()       */
  1632. /*                                                                    */
  1633. /*     Results returned:                                              */
  1634. /*        PASSED     Operation successful                             */
  1635. /*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
  1636. /*                                                                    */
  1637. /*     Calls: allocate_new_directory_page()                           */
  1638. /*            map_dir_page()                                          */
  1639. /*            break_overlap()                                         */
  1640. /*            find_new_dir_start()                                    */
  1641. /*                                                                    */
  1642. /*     Called by: efmalloc()                                          */
  1643. /*                                                                    */
  1644. /*     Globals referenced/modified: dir_page_count                    */
  1645. /*                                  directory                         */
  1646. /*                                  directory_map                     */
  1647. /*                                  dir_start                         */
  1648. /*                                  dir_end                           */
  1649. /*                                                                    */
  1650. /**********************************************************************/
  1651.   
  1652. unsigned int check_best_fit (size, best_index, min_difference)
  1653. unsigned int size;
  1654. unsigned int *best_index;
  1655. long         *min_difference;
  1656. {
  1657.     unsigned int index;                  /* Index into a directory page      */
  1658.     unsigned int status;                 /* Status of EMM and MEMLIB         */
  1659.     unsigned int page;                   /* Directory page to map in         */
  1660.     unsigned int size_mod_page_size;     /* Size of block MOD PAGE_SIZE      */
  1661.     unsigned int free_space;             /* The free space before a page     */
  1662.                                         /* boundry in a free block          */
  1663.     unsigned int dir_starts_page;        /* Dir_start's dir entry's log page */
  1664.     long         this_ones_min_diff;     /* Current block's min difference   */
  1665.     unsigned int this_ones_offset;       /* Current block's offset into a    */
  1666.                                         /* logical page                     */
  1667.     long         new_size;               /* Free space after page boundry    */
  1668.     unsigned int found_exact_fit;        /* Whether we found an exact fit    */
  1669.     unsigned int overlap;                /* Whether we have an overlapping   */
  1670.                                         /* block                            */
  1671.     long         overlap_min_difference; /* Minimum difference for the       */
  1672.                                         /* overlapping block                */
  1673.   
  1674.    /************************************************/
  1675.    /* Initialize variables for best fit algorithm. */
  1676.    /************************************************/
  1677.   
  1678.     index                  = dir_start % DIR_ENTRIES_PER_PAGE;
  1679.     *best_index            = UNASSIGNED_TOKEN;
  1680.     found_exact_fit        = FALSE;
  1681.     overlap                = FALSE;
  1682.     *min_difference        = LARGEST_ALLOCATABLE_BLOCK;
  1683.     status                 = PASSED;
  1684.     overlap_min_difference = LARGEST_ALLOCATABLE_BLOCK;
  1685.     size_mod_page_size     = size % PAGE_SIZE;
  1686.   
  1687.     if (size_mod_page_size == 0)
  1688.         size_mod_page_size = PAGE_SIZE;
  1689.   
  1690.    /**************************************************/
  1691.    /* Make sure a new directory page is allocated    */
  1692.    /* before it is needed.  This done so the a block */
  1693.    /* that has free mem will not be lost to the      */
  1694.    /* the purple zone before a new directory page    */
  1695.    /* is allocated in allocate_new_block().         */
  1696.    /* Allocate_new_directory_page() is called when   */
  1697.    /* the current directory entries is two from      */
  1698.    /* being filled up.                               */
  1699.    /**************************************************/
  1700.   
  1701.     if (dir_end >= (unsigned int) (NUM_DIR_ENTRIES (dir_page_count) - 2))
  1702.         status = allocate_new_directory_page();
  1703.   
  1704.     if (status == PASSED)
  1705.     {
  1706.         dir_starts_page = dir_start / DIR_ENTRIES_PER_PAGE;
  1707.   
  1708.       /*****************************************/
  1709.       /* Go through all of the directory pages */
  1710.       /* until we find an exact fit.           */
  1711.       /*****************************************/
  1712.   
  1713.         for (page = dir_starts_page; ((page < dir_page_count) &&
  1714.             (!found_exact_fit) &&
  1715.             (status == PASSED)); page++)
  1716.         {
  1717.          /**********************************/
  1718.          /* Map in the this directory page */
  1719.          /**********************************/
  1720.   
  1721.             status = map_dir_page (page, FIRST_PHYS_PAGE);
  1722.             if (status == PASSED)
  1723.             {
  1724.             /*********************************************************/
  1725.             /* Go through the current page looking for the best fit. */
  1726.             /*********************************************************/
  1727.   
  1728.                 while ((index < DIR_ENTRIES_PER_PAGE) &&
  1729.                     ((index + page * DIR_ENTRIES_PER_PAGE) <= dir_end) &&
  1730.                     (!found_exact_fit))
  1731.                 {
  1732.                /*****************************************/
  1733.                /* If this block of memory is available. */
  1734.                /*****************************************/
  1735.   
  1736.                     if (directory[0][index].token == UNASSIGNED_TOKEN)
  1737.                     {
  1738.                   /************************************************/
  1739.                   /* If size is 0 then this block is unallocated. */
  1740.                   /************************************************/
  1741.   
  1742.                         if (directory[0][index].size == 0)
  1743.                         {
  1744.                      /*********************************************/
  1745.                      /* If best_index = UNASSIGNED_TOKEN we       */
  1746.                      /* haven't found any previous blocks to use. */
  1747.                      /*********************************************/
  1748.   
  1749.                             if (*best_index == UNASSIGNED_TOKEN)
  1750.                                 *best_index = index + (page * DIR_ENTRIES_PER_PAGE);
  1751.                         }
  1752.                         else
  1753.                         {
  1754.                      /************************************************/
  1755.                      /* This is a previously freed block and we need */
  1756.                      /* to check how close of a fit it is.           */
  1757.                      /************************************************/
  1758.   
  1759.                             this_ones_min_diff = (long) directory[0][index].size - size;
  1760.                             if ((this_ones_min_diff >= 0) &&
  1761.                                 (this_ones_min_diff < *min_difference))
  1762.                             {
  1763.                         /**************************************/
  1764.                         /* If exact fit then take this block. */
  1765.                         /**************************************/
  1766.   
  1767.                                 if (this_ones_min_diff == 0)
  1768.                                 {
  1769.                                     found_exact_fit = TRUE;
  1770.                                     *best_index     = index + (page * DIR_ENTRIES_PER_PAGE);
  1771.                                     *min_difference = 0;
  1772.                                     overlap         = FALSE;
  1773.                                 }
  1774.                                 else
  1775.                                 {
  1776.                            /***********************************************/
  1777.                            /* Make sure that putting the newly allocated  */
  1778.                            /* block at the beginning of the free block    */
  1779.                            /* won't cause the new block to overlap more   */
  1780.                            /* logical pages than it needs.                */
  1781.                            /*                                             */
  1782.                            /* If the remainder of the requested block     */
  1783.                            /* size MOD PAGE_SIZE will fit in the first    */
  1784.                            /* logical page of the freed block, then the   */
  1785.                            /* requested block will fit correctly.         */
  1786.                            /***********************************************/
  1787.   
  1788.                            /*******************************************/
  1789.                            /* Where this free block starts within its */
  1790.                            /* first logical page.                     */
  1791.                            /*******************************************/
  1792.   
  1793.                                     this_ones_offset = directory[0][index].offset;
  1794.   
  1795.                            /********************************************/
  1796.                            /* The room left on the first logical page. */
  1797.                            /********************************************/
  1798.   
  1799.                                     free_space = PAGE_SIZE - this_ones_offset;
  1800.   
  1801.                                     if (free_space >= size_mod_page_size)
  1802.                                     {
  1803.                               /******************************************/
  1804.                               /* The block will fit just fine.  We will */
  1805.                               /* have the block itself and a remainder. */
  1806.                               /******************************************/
  1807.   
  1808.                                         *best_index     = index + (page * DIR_ENTRIES_PER_PAGE);
  1809.                                         *min_difference = this_ones_min_diff;
  1810.                                         overlap         = FALSE;
  1811.                                     }
  1812.                                     else
  1813.                                     {
  1814.                               /********************************************/
  1815.                               /* The new block will fit but we have to    */
  1816.                               /* start it on this free block's first page */
  1817.                               /* boundry.  We will need to keep track of  */
  1818.                               /* the space before the page boundry, the   */
  1819.                               /* new block, and any remainder from the    */
  1820.                               /* new block.  We will have an overlap to   */
  1821.                               /* break.                                   */
  1822.                               /********************************************/
  1823.   
  1824.                                         new_size = (long) directory[0][index].size - free_space;
  1825.                                         if (new_size >= size)
  1826.                                         {
  1827.                                             overlap = TRUE;
  1828.                                             this_ones_min_diff = new_size - size;
  1829.                                             if (this_ones_min_diff < overlap_min_difference)
  1830.                                             {
  1831.                                                 overlap_min_difference = new_size - size;
  1832.                                                 *best_index = index + (page * DIR_ENTRIES_PER_PAGE);
  1833.                                             }
  1834.                                         }
  1835.                                     } /** end else **/
  1836.   
  1837.                                 } /** end else **/
  1838.   
  1839.                             } /** end if temp_difference ... **/
  1840.   
  1841.                         } /** end else **/
  1842.   
  1843.                     } /** end if directory **/
  1844.   
  1845.                     index++;
  1846.   
  1847.                 } /** end while **/
  1848.   
  1849.             } /** end if passed **/
  1850.             index = 0;
  1851.   
  1852.         } /** end if page **/
  1853.   
  1854.       /**********************************************/
  1855.       /* If we have an overlap we need to break it. */
  1856.       /**********************************************/
  1857.   
  1858.         if ((overlap) &&
  1859.             (status == PASSED))
  1860.         {
  1861.             *min_difference = overlap_min_difference;
  1862.             status = break_overlap (best_index);
  1863.         }
  1864.   
  1865.       /****************************************************/
  1866.       /* Update our starting entry if the current one ==  */
  1867.       /* to best_index and we don't have an overlap.      */
  1868.       /****************************************************/
  1869.   
  1870.         if ((dir_start == *best_index) &&
  1871.             (!overlap) &&
  1872.             (status == PASSED))
  1873.             status = find_new_dir_start();
  1874.   
  1875.       /**************************************/
  1876.       /* Update our ending entry if needed. */
  1877.       /**************************************/
  1878.   
  1879.         if ((*best_index >= dir_end) &&
  1880.             (status == PASSED))
  1881.             dir_end = *best_index + 1;
  1882.   
  1883.     } /** end if passed **/
  1884.   
  1885.     return (status);
  1886.   
  1887. } /* end check_best_fit() */
  1888.   
  1889. /*$PAGE*/
  1890. /**********************************************************************/
  1891. /*                                                                    */
  1892. /*     Name: unsigned int check_if_all_blocks_free (all_blocks_free)  */
  1893. /*           unsigned int *all_blocks_free;                           */
  1894. /*                                                                    */
  1895. /*     Description:                                                   */
  1896. /*        If the block being freed by effree() is the last one to be  */
  1897. /*     freed then we need to deallocate all the pages allocated to    */
  1898. /*     this application.  This tells us that the program using MEMLIB */
  1899. /*     may be terminating and we want to be sure that all pages for   */
  1900. /*     this application have been deallocated.  This function will    */
  1901. /*     see if there are any blocks left in the directory that are     */
  1902. /*     allocated and if not, will deallocate all pages that this      */
  1903. /*     application owns.                                              */
  1904. /*                                                                    */
  1905. /*     Parameters:                                                    */
  1906. /*        output  free_status     TRUE - all blocks are free          */
  1907. /*                                FALSE - there are some blocks used  */
  1908. /*                                                                    */
  1909. /*     Results returned:                                              */
  1910. /*        PASSED    Operation successful                              */
  1911. /*        error     Non-zero value, see "ERRORS.H" or EMS table A-2   */
  1912. /*                                                                    */
  1913. /*     Calls: map_dir_page()                                          */
  1914. /*                                                                    */
  1915. /*     Called by: effree()                                            */
  1916. /*                                                                    */
  1917. /*     Globals referenced/modified: dir_page_count                    */
  1918. /*                                  directory                         */
  1919. /*                                  directory_map                     */
  1920. /*                                                                    */
  1921. /**********************************************************************/
  1922.   
  1923. unsigned int check_if_all_blocks_free (all_blocks_free)
  1924. unsigned int *all_blocks_free;
  1925. {
  1926.     unsigned int status;       /* Status of EMM and MEMLIB          */
  1927.     unsigned int page;         /* Current directory page mapped in  */
  1928.     unsigned int index;        /* Current index into a logical page */
  1929.   
  1930.    /******************************/
  1931.    /* Assume all blocks are free */
  1932.    /* and status OK.             */
  1933.    /******************************/
  1934.   
  1935.     *all_blocks_free = TRUE;
  1936.     status           = PASSED;
  1937.   
  1938.    /**************************************************************/
  1939.    /* Loop through the directory, checking for non-freed blocks. */
  1940.    /**************************************************************/
  1941.   
  1942.     for (page = 0; ((page < dir_page_count) &&
  1943.         (*all_blocks_free) &&
  1944.         (status == PASSED)); page++)
  1945.     {
  1946.       /*******************************/
  1947.       /* Map in this directory page. */
  1948.       /*******************************/
  1949.   
  1950.         status = map_dir_page (page, FIRST_PHYS_PAGE);
  1951.         if (status == PASSED)
  1952.         {
  1953.          /************************************/
  1954.          /* Check all index's for this page. */
  1955.          /************************************/
  1956.   
  1957.             for (index = 0; ((index < DIR_ENTRIES_PER_PAGE) &&
  1958.                 (*all_blocks_free)); index++)
  1959.             {
  1960.                 if (directory[0][index].token != UNASSIGNED_TOKEN)
  1961.                 {
  1962.                /**********************************************/
  1963.                /* If we find a block that's being used, set  */
  1964.                /* all_block_free to FALSE and stop checking. */
  1965.                /**********************************************/
  1966.   
  1967.                     *all_blocks_free = FALSE;
  1968.                 }
  1969.             } /** end for index **/
  1970.   
  1971.         } /** end if status PASSED **/
  1972.   
  1973.     } /** end for page **/
  1974.   
  1975.     return (status);
  1976.   
  1977. }  /** end if_all_blocks_free **/
  1978.   
  1979.   
  1980. /*$PAGE*/
  1981. /**********************************************************************/
  1982. /*                                                                    */
  1983. /*     Name:  unsigned int coalesce_block (block1, block2, coalasce)  */
  1984. /*            unsigned int block1;                                    */
  1985. /*            unsigned int block2;                                    */
  1986. /*            unsigned int *coalesce;                                 */
  1987. /*                                                                    */
  1988. /*     Description:                                                   */
  1989. /*        This coalesces one block of free expanded memory (block1)   */
  1990. /*     to another (block2).                                           */
  1991. /*                                                                    */
  1992. /*     Parameters:                                                    */
  1993. /*        input    block1      The identifier for the first block.    */
  1994. /*                 block2      The identifier for the second block.   */
  1995. /*         output  coalesce    Whether we really coalesced or not.    */
  1996. /*                                                                    */
  1997. /*     Results returned:                                              */
  1998. /*        PASSED     Coalescing successful or not needed              */
  1999. /*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
  2000. /*                                                                    */
  2001. /*     Calls: map_dir_page()                                          */
  2002. /*            get_context()                                           */
  2003. /*            set_context()                                           */
  2004. /*                                                                    */
  2005. /*     Called by:  search_before()                                    */
  2006. /*                 search_after()                                     */
  2007. /*                                                                    */
  2008. /*     Globals referenced/modified: directory                         */
  2009. /*                                  directory_map                     */
  2010. /*                                                                    */
  2011. /**********************************************************************/
  2012.   
  2013. unsigned int coalesce_block (block1, block2, coalesce)
  2014. unsigned int block1;
  2015. unsigned int block2;
  2016. unsigned int *coalesce;
  2017. {
  2018.     unsigned int   j;              /* Looping variable                     */
  2019.     unsigned int   block1s_page;   /* Block1's directory entry's log page  */
  2020.     unsigned int   block1s_index;  /* Block1's index into its logical page */
  2021.     unsigned int   block2s_page;   /* Block2's directory entry's log page  */
  2022.     unsigned int   block2s_index;  /* Block2's index into its logical page */
  2023.     unsigned int   end_of_block2;  /* End of block2 (size+offset)          */
  2024.     unsigned int   start_page;     /* Starting logical page for coalescing */
  2025.     unsigned int   status;         /* Status of EMM and MEMLIB             */
  2026.     CONTEXT_STRUCT context;        /* For storing the current context      */
  2027.   
  2028.    /******************************************************************/
  2029.    /* We need to continue where we left off from when we return      */
  2030.    /* to search_before() or search_after(), so we need to save       */
  2031.    /* the pages they had mapped in before they called this function. */
  2032.    /******************************************************************/
  2033.   
  2034.     status = get_context (&context);
  2035.     if (status == PASSED)
  2036.     {
  2037.       /**************************************************************/
  2038.       /* Convert block1 to its respective directory page and index. */
  2039.       /**************************************************************/
  2040.   
  2041.         block1s_page  = block1 / DIR_ENTRIES_PER_PAGE;
  2042.         block1s_index = block1 % DIR_ENTRIES_PER_PAGE;
  2043.   
  2044.       /***********************************/
  2045.       /* Map in block1's directory page. */
  2046.       /***********************************/
  2047.   
  2048.         status = map_dir_page (block1s_page, FIRST_PHYS_PAGE);
  2049.     }
  2050.   
  2051.     if (status == PASSED)
  2052.     {
  2053.       /*********************************************************/
  2054.       /* Convert block1 to its respective directory page and   */
  2055.       /* index.  We're going to map this page into the second  */
  2056.       /* physical page.  In order to access this pages entries */
  2057.       /* we need to offset its indexes by DIR_ENTRIES_PER_PAGE */
  2058.       /* from the beginning of the first physical page.        */
  2059.       /*********************************************************/
  2060.   
  2061.         block2s_page  = block2 / DIR_ENTRIES_PER_PAGE;
  2062.         block2s_index = block2 % DIR_ENTRIES_PER_PAGE;
  2063.   
  2064.       /*****************************************************/
  2065.       /* Map in block2's directory page using the          */
  2066.       /* directory_map's second array element to map this  */
  2067.       /* page in at physical page one while keeping        */
  2068.       /* block1's  directory page at physical page zero.   */
  2069.       /*****************************************************/
  2070.   
  2071.         status = map_dir_page (block2s_page, SECOND_PHYS_PAGE);
  2072.   
  2073.       /****************************/
  2074.       /* Coalesce the two blocks. */
  2075.       /****************************/
  2076.   
  2077.         if (status == PASSED)
  2078.         {
  2079.          /****************************************/
  2080.          /* Assume we will coalesce these blocks */
  2081.          /****************************************/
  2082.   
  2083.             *coalesce = TRUE;
  2084.   
  2085.          /*********************************************/
  2086.          /* Set the starting logical page for block2. */
  2087.          /*********************************************/
  2088.   
  2089.             end_of_block2 = (directory[1][block2s_index].offset +
  2090.             directory[1][block2s_index].size) % PAGE_SIZE;
  2091.   
  2092.             if (end_of_block2 == 0)
  2093.                 start_page = NUM_PAGES (directory[1][block2s_index].size);
  2094.             else
  2095.                 start_page = NUM_PAGES (directory[1][block2s_index].size) - 1;
  2096.   
  2097.          /********************************************************/
  2098.          /* If combining the blocks would cause too many logical */
  2099.          /* pages to be used, DON'T coalesce them.               */
  2100.          /********************************************************/
  2101.   
  2102.             if ((start_page + NUM_PAGES (directory[0][block1s_index].size))
  2103.                 >= MAX_ALLOCATABLE_PAGES)
  2104.                 *coalesce = FALSE;
  2105.   
  2106.             if (*coalesce)
  2107.             {
  2108.   
  2109.             /*****************************************************/
  2110.             /* Combine the logical pages for block1 into block2. */
  2111.             /*****************************************************/
  2112.   
  2113.                 for (j = 0; j < NUM_PAGES (directory[0][block1s_index].size); j++)
  2114.                 {
  2115.                     directory[1][block2s_index].logical_page[start_page + j] =
  2116.                     directory[0][block1s_index].logical_page[j];
  2117.                 }
  2118.   
  2119.             /******************************************/
  2120.             /* Set block2's size to the combined size */
  2121.             /* and zero out block 1.                  */
  2122.             /******************************************/
  2123.   
  2124.                 directory[1][block2s_index].size += directory[0][block1s_index].size;
  2125.                 directory[0][block1s_index].size = 0;
  2126.   
  2127.             }
  2128.         }
  2129.     }
  2130.   
  2131.    /************************************/
  2132.    /* Restore the pages that were here */
  2133.    /* before this function was called. */
  2134.    /************************************/
  2135.   
  2136.     if (status == PASSED)
  2137.         status = set_context (&context);
  2138.   
  2139.     return (status);
  2140.   
  2141. } /** end coalesce_block() **/
  2142.   
  2143. /*$PAGE*/
  2144. /**********************************************************************/
  2145. /*                                                                    */
  2146. /*     Name:  unsigned int search_after (token, final_entry,          */
  2147. /*                                         usable_entry)              */
  2148. /*            unsigned int token;                                     */
  2149. /*            unsigned int *final_entry;                              */
  2150. /*            unsigned int *usable_entry;                             */
  2151. /*                                                                    */
  2152. /*     Description:                                                   */
  2153. /*        This function searches for a free block of memory after the */
  2154. /*     block of memory we just freed.  This is done in order to       */
  2155. /*     coalesce the two blocks.                                       */
  2156. /*                                                                    */
  2157. /*     Parameters:                                                    */
  2158. /*        input   token        The token of the block of memory       */
  2159. /*                             that's been freed                      */
  2160. /*        output  final_entry  The directory entry of the final       */
  2161. /*                             coalesced block or unassigned if no    */
  2162. /*                             blocks were found.                     */
  2163. /*                usable_entry The directory entry of a usable block  */
  2164. /*                                                                    */
  2165. /*     Results returned:                                              */
  2166. /*        PASSED     Operation successful                             */
  2167. /*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
  2168. /*                                                                    */
  2169. /*     Calls: coalesce_block()                                        */
  2170. /*            map_dir_page()                                          */
  2171. /*                                                                    */
  2172. /*     Called by: effree()                                            */
  2173. /*                                                                    */
  2174. /*     Globals referenced/modified: directory                         */
  2175. /*                                  directory_map                     */
  2176. /*                                  dir_page_count                    */
  2177. /*                                                                    */
  2178. /**********************************************************************/
  2179.   
  2180. unsigned int search_after (token, final_entry, usable_entry)
  2181. unsigned int token;
  2182. unsigned int *final_entry;
  2183. unsigned int *usable_entry;
  2184. {
  2185.     unsigned int index;              /* Index into a directory page         */
  2186.     unsigned int indexs_entry;       /* Index translated to a full dir entry*/
  2187.     unsigned int coalesce;           /* Whether we should coalesce or not   */
  2188.     unsigned int tokens_last_page;   /* Last logical page for token's block */
  2189.     unsigned int end_of_tokens_block;/* The end of token's block            */
  2190.     unsigned int page;               /* Directory pages to loop through     */
  2191.     unsigned int tokens_page;        /* Token's directory entry's log page  */
  2192.     unsigned int tokens_index;       /* Token's index into its logical page */
  2193.     unsigned int status;             /* Status of EMM and MEMLIB            */
  2194.   
  2195.    /****************************************************************/
  2196.    /* Convert the token passed in to its respective directory page */
  2197.    /* and index.  We're going to map this page into the second     */
  2198.    /* physical page.  In order to access this pages entries we     */
  2199.    /* need to use second_dir_page.                                 */
  2200.    /****************************************************************/
  2201.   
  2202.     tokens_page  = token / DIR_ENTRIES_PER_PAGE;
  2203.     tokens_index = token % DIR_ENTRIES_PER_PAGE;
  2204.   
  2205.    /*********************************************************/
  2206.    /* Map in the token's directory page using the           */
  2207.    /* directory_map's second array element to map this page */
  2208.    /* in at physical page one while keeping the block to be */
  2209.    /* coalesced's directory page at physical page zero.     */
  2210.    /*********************************************************/
  2211.   
  2212.     status = map_dir_page (tokens_page, SECOND_PHYS_PAGE);
  2213.     if (status == PASSED)
  2214.     {
  2215.       /**********************************/
  2216.       /* Find the end of token's block. */
  2217.       /**********************************/
  2218.   
  2219.         end_of_tokens_block = (directory[1][tokens_index].size +
  2220.         directory[1][tokens_index].offset) % PAGE_SIZE;
  2221.   
  2222.       /**************************/
  2223.       /* Set variables for loop */
  2224.       /**************************/
  2225.   
  2226.         *final_entry     = UNASSIGNED_TOKEN;
  2227.         tokens_last_page = NUM_PAGES (directory[1][tokens_index].size) - 1;
  2228.         coalesce         = FALSE;
  2229.   
  2230.       /******************************************************/
  2231.       /* Search for a free block of memory after this block */
  2232.       /* to coalesce into one free block.                   */
  2233.       /******************************************************/
  2234.   
  2235.         for (page = 0; ((page < dir_page_count) &&
  2236.             (status == PASSED) &&
  2237.             (!coalesce)); page++)
  2238.         {
  2239.          /*******************************/
  2240.          /* Map in this directory page. */
  2241.          /*******************************/
  2242.   
  2243.             status = map_dir_page (page, FIRST_PHYS_PAGE);
  2244.          /*********************************************/
  2245.          /* Go through all the indexes for this page. */
  2246.          /*********************************************/
  2247.   
  2248.             for (index = 0; ((index < DIR_ENTRIES_PER_PAGE) &&
  2249.                 (status == PASSED) &&
  2250.                 (!coalesce)); index++)
  2251.             {
  2252.             /********************************************/
  2253.             /* Convert index to a full directory entry. */
  2254.             /********************************************/
  2255.   
  2256.                 indexs_entry = index + page * DIR_ENTRIES_PER_PAGE;
  2257.   
  2258.             /*********************************************************/
  2259.             /* For index's block test:                               */
  2260.             /* Is it free?                                           */
  2261.             /* Is it > 0?                                            */
  2262.             /* Is it different than the block we called effree with? */
  2263.             /* Would its size make a coalesced block > 64K?          */
  2264.             /*********************************************************/
  2265.   
  2266.                 if ((directory[0][index].token == UNASSIGNED_TOKEN) &&
  2267.                     (directory[0][index].size > 0) &&
  2268.                     (indexs_entry != token) &&
  2269.                     ((unsigned long) directory[0][index].size +
  2270.                     directory[1][tokens_index].size < K64K))
  2271.                 {
  2272.                /****************************************************/
  2273.                /* If the end of token's block equals the beginning */
  2274.                /* of index's block then index's block could lie    */
  2275.                /* AFTER our block.                                 */
  2276.                /****************************************************/
  2277.   
  2278.                     if (end_of_tokens_block == directory[0][index].offset)
  2279.                     {
  2280.                   /******************************************************/
  2281.                   /* Test the logical pages for these two blocks to     */
  2282.                   /* see if we want to coalesce them.  We will coalesce */
  2283.                   /* if either of the following is true:                */
  2284.                   /*                                                    */
  2285.                   /* 1. If the token's block ends on an exact page      */
  2286.                   /*    boundry (end_of_tokens_block == 0) then we do   */
  2287.                   /*    NOT want the last logical page of token's block */
  2288.                   /*    to match the first logical page of index's      */
  2289.                   /*    block.                                          */
  2290.                   /*                                                    */
  2291.                   /* 2. If token's block ends in the middle of a        */
  2292.                   /*    logical page (end_of_tokens_block != 0) the we  */
  2293.                   /*    DO want token's block's last logical page to    */
  2294.                   /*    match index's block's first logical page.       */
  2295.                   /******************************************************/
  2296.   
  2297.                         if (end_of_tokens_block == 0)
  2298.                         {
  2299.                             if (directory[1][tokens_index].logical_page[tokens_last_page]
  2300.                                 != directory[0][index].logical_page[0])
  2301.                             {
  2302.                                 coalesce = TRUE;
  2303.                             }
  2304.                         }
  2305.                         else
  2306.                         {
  2307.                             if (directory[1][tokens_index].logical_page[tokens_last_page]
  2308.                                 == directory[0][index].logical_page[0])
  2309.                             {
  2310.                                 coalesce = TRUE;
  2311.                             }
  2312.                         }
  2313.                         if (coalesce)
  2314.                         {
  2315.                      /************************************/
  2316.                      /* We've got a winner! Coalesce the */
  2317.                      /* i'th block into our block.       */
  2318.                      /************************************/
  2319.   
  2320.                             status = coalesce_block (indexs_entry, token, &coalesce);
  2321.   
  2322.                             if ((status == PASSED) && coalesce)
  2323.                             {
  2324.                                 *final_entry  = token;
  2325.                                 *usable_entry = indexs_entry;
  2326.                             }
  2327.   
  2328.                         } /** end if coalesce **/
  2329.   
  2330.                     } /** end if end_of_tokens_block **/
  2331.   
  2332.                 }  /** end if directory **/
  2333.   
  2334.             }  /** end for index **/
  2335.   
  2336.         }  /** end for page **/
  2337.   
  2338.     } /** end if PASSED **/
  2339.   
  2340.     return (status);
  2341.   
  2342. } /** end search_after() **/
  2343.   
  2344. /*$PAGE*/
  2345. /**********************************************************************/
  2346. /*                                                                    */
  2347. /*     Name:  unsigned int search_before (token, final_entry,         */
  2348. /*                                          usable_entry)             */
  2349. /*            unsigned int token;                                     */
  2350. /*            unsigned int *final_entry;                              */
  2351. /*            unsigned int *usable_entry;                             */
  2352. /*                                                                    */
  2353. /*     Description:                                                   */
  2354. /*        This function searches for a free block of memory before    */
  2355. /*     the block of memory we just freed.  This is done in order to   */
  2356. /*     coalesce the two blocks.                                       */
  2357. /*                                                                    */
  2358. /*     Parameters:                                                    */
  2359. /*        input   token        The token of the block of memory       */
  2360. /*                             that's been freed                      */
  2361. /*        output  final_entry  The directory entry of the final       */
  2362. /*                             coalesced block or unassigned if no    */
  2363. /*                             blocks were found.                     */
  2364. /*                temp_entry   The directory entry of a usable block  */
  2365. /*                                                                    */
  2366. /*     Results returned:                                              */
  2367. /*        PASSED     Operation successful                             */
  2368. /*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
  2369. /*                                                                    */
  2370. /*     Calls: coalesce_block()                                        */
  2371. /*            map_dir_page()                                          */
  2372. /*                                                                    */
  2373. /*     Called by: effree()                                            */
  2374. /*                                                                    */
  2375. /*     Globals referenced/modified: directory                         */
  2376. /*                                  directory_map                     */
  2377. /*                                  dir_page_count                    */
  2378. /*                                                                    */
  2379. /**********************************************************************/
  2380.   
  2381. unsigned int search_before (token, final_entry, usable_entry)
  2382. unsigned int token;
  2383. unsigned int *final_entry;
  2384. unsigned int *usable_entry;
  2385. {
  2386.     unsigned int index;              /* Index into a directory page          */
  2387.     unsigned int indexs_entry;       /* Index translated to a full dir entry */
  2388.     unsigned int indexs_last_page;   /* Last logical page for index's block  */
  2389.     unsigned int coalesce;           /* Whether we should coalesce or not    */
  2390.     unsigned int end_of_indexs_block;/* The end of token's block             */
  2391.     unsigned int page;               /* Directory pages to loop through      */
  2392.     unsigned int tokens_page;        /* Token's directory entry's log page   */
  2393.     unsigned int tokens_index;       /* Token's index into its logical page  */
  2394.     unsigned int status;             /* Status of EMM and MEMLIB             */
  2395.   
  2396.    /****************************************************************/
  2397.    /* Convert the token passed in to its respective directory page */
  2398.    /* and index.  We're going to map this page into the second     */
  2399.    /* physical page.  In order to access this page's entries we    */
  2400.    /* need to use directory[1].                                    */
  2401.    /****************************************************************/
  2402.   
  2403.     tokens_page  = token / DIR_ENTRIES_PER_PAGE;
  2404.     tokens_index = token % DIR_ENTRIES_PER_PAGE;
  2405.   
  2406.    /*********************************************************/
  2407.    /* Map in the token's directory page using the           */
  2408.    /* directory_map's second array element to map this page */
  2409.    /* in at physical page one while keeping the block to be */
  2410.    /* coalesced's directory page at physical page zero.     */
  2411.    /*********************************************************/
  2412.   
  2413.     status = map_dir_page (tokens_page, SECOND_PHYS_PAGE);
  2414.     if (status == PASSED)
  2415.     {
  2416.       /***************************/
  2417.       /* Set variables for loop. */
  2418.       /***************************/
  2419.   
  2420.         coalesce = FALSE;
  2421.   
  2422.       /*************************************************/
  2423.       /* Search for a free block of memory before this */
  2424.       /* block to coalesce into one free block.        */
  2425.       /*************************************************/
  2426.   
  2427.         for (page = 0; ((page < dir_page_count) &&
  2428.             (status == PASSED) &&
  2429.             (!coalesce)); page++)
  2430.         {
  2431.          /*******************************/
  2432.          /* Map in this directory page. */
  2433.          /*******************************/
  2434.   
  2435.             status = map_dir_page (page, FIRST_PHYS_PAGE);
  2436.   
  2437.          /*********************************************/
  2438.          /* Go through all the indexes for this page. */
  2439.          /*********************************************/
  2440.   
  2441.             for (index = 0; ((index < DIR_ENTRIES_PER_PAGE) &&
  2442.                 (status == PASSED) &&
  2443.                 (!coalesce)); index++)
  2444.             {
  2445.             /********************************************/
  2446.             /* Convert index to a full directory entry. */
  2447.             /********************************************/
  2448.   
  2449.                 indexs_entry = index + page * DIR_ENTRIES_PER_PAGE;
  2450.   
  2451.             /*********************************************************/
  2452.             /* For index's block test:                               */
  2453.             /* Is it free?                                           */
  2454.             /* Is it > 0?                                            */
  2455.             /* Is it different than the block we called effree with? */
  2456.             /* Would its size make a coalesced block > 64K?          */
  2457.             /*********************************************************/
  2458.   
  2459.                 if ((directory[0][index].token == UNASSIGNED_TOKEN) &&
  2460.                     (directory[0][index].size > 0) &&
  2461.                     (indexs_entry != token) &&
  2462.                     ((unsigned long) directory[0][index].size +
  2463.                     directory[1][tokens_index].size < K64K))
  2464.                 {
  2465.                     end_of_indexs_block = (directory[0][index].offset +
  2466.                     directory[0][index].size) % PAGE_SIZE;
  2467.   
  2468.                     indexs_last_page = NUM_PAGES (directory[0][index].size) - 1;
  2469.   
  2470.   
  2471.                /*********************************************/
  2472.                /* If the beginning of token's block exactly */
  2473.                /* matches the end of index's block then     */
  2474.                /* index's block could lie BEFORE our block. */
  2475.                /*********************************************/
  2476.   
  2477.                     if (directory[1][tokens_index].offset == end_of_indexs_block)
  2478.                     {
  2479.                   /******************************************************/
  2480.                   /* Test the logical pages for these two blocks to     */
  2481.                   /* see if we want to coalesce them.  We will coalesce */
  2482.                   /* if either of the following is true:                */
  2483.                   /*                                                    */
  2484.                   /* 1. If the token's block ends on an exact page      */
  2485.                   /*    boundry (end_of_indexs_block == 0) then we do   */
  2486.                   /*    NOT want the first logical page of token's      */
  2487.                   /*    block to match the last logical page of index's */
  2488.                   /*    block.                                          */
  2489.                   /*                                                    */
  2490.                   /* 2. If token's block ends in the middle of a        */
  2491.                   /*    logical page (end_of_indexs_block != 0) the we  */
  2492.                   /*    DO want token's block's first logical page to   */
  2493.                   /*    match index's block's last logical page.        */
  2494.                   /******************************************************/
  2495.   
  2496.                         if (end_of_indexs_block == 0)
  2497.                         {
  2498.                             if (directory[0][index].logical_page[indexs_last_page] !=
  2499.                                 directory[1][tokens_index].logical_page[0])
  2500.                             {
  2501.                                 coalesce   = TRUE;
  2502.                             }
  2503.                         }
  2504.                         else
  2505.                         {
  2506.                             if (directory[0][index].logical_page[indexs_last_page] ==
  2507.                                 directory[1][tokens_index].logical_page[0])
  2508.                             {
  2509.                                 coalesce   = TRUE;
  2510.                             }
  2511.                         }
  2512.                         if (coalesce)
  2513.                         {
  2514.                      /************************************/
  2515.                      /* We've got a winner! Coalesce the */
  2516.                      /* i'th block into our block.       */
  2517.                      /************************************/
  2518.   
  2519.                             status = coalesce_block (token, indexs_entry, &coalesce);
  2520.   
  2521.                             if ((status == PASSED) &&
  2522.                                 coalesce)
  2523.                             {
  2524.                                 *final_entry  = indexs_entry;
  2525.                                 *usable_entry = token;
  2526.                             }
  2527.   
  2528.                         } /** end if coalesce **/
  2529.   
  2530.                     } /** end if directory **/
  2531.   
  2532.                 }  /** end if directory **/
  2533.   
  2534.             }  /** end for index = 0 **/
  2535.   
  2536.         }  /** end for page **/
  2537.   
  2538.     } /** end if PASSED **/
  2539.   
  2540.     return (status);
  2541. }  /** end search_before() **/
  2542.   
  2543.   
  2544.   
  2545.   
  2546.   
  2547.