home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 10 / 10.iso / l / l440 / 2.ddi / CHAP5 / MULTI.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-09-26  |  10.7 KB  |  388 lines

  1. /* MULTI.C */
  2.  
  3. #include <stddef.h>
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include <dos.h>
  8. #include <io.h>
  9. #include "tsr.h"
  10.  
  11. #define SEARCH_DIR   "C:\\SPOOL\\"
  12. #define STACK_SIZE  4096    /* must be 16 byte boundaray */
  13. #define SET_DTA     0x1a  /* SET Disk Transfer Address */
  14. #define GET_DTA     0x2f  /* GET Disk  Transfer Address */
  15.  
  16. #define BACKGROUND_TICS 2
  17. #define FOREGROUND_TICS 16
  18. #define BACKGROUND_YIELD 0
  19. #define FOREGROUND_YIELD 0
  20.  
  21. struct  prReq
  22. {
  23.     char level;
  24.     char far *fname;
  25. };
  26.  
  27. char    far *stack_ptr;   /* stack for our background TSR */
  28. char    far *ptr;
  29. unsigned ss_save;         /* slot for stack segment register */
  30. unsigned sp_save;         /* slot for stack pointer register */
  31. unsigned unsafe_flag = 0; /* set true by variouse interrupts */
  32. int first_time = 1;       /* flag for first time in running background */
  33.  
  34. int my_psp;               /* our TSR's psp */
  35. int foreground_psp;       /* PSP of interrupted foreground process */
  36. int foreground_dta_seg;   /* DTA of interrupted foreground process */
  37. int foreground_dta_off;
  38. int ctr=0; 
  39. int tic_count = 0;        /* counts timer tices */
  40. int in_progress = 0;      /* true if we're in background process */
  41.  
  42. char search_work[65];       
  43. struct ExtErr my_ErrInfo;
  44. struct ExtErr foreground_ErrInfo;
  45.  
  46. int foreground_limit = FOREGROUND_TICS; /* foreground cycle limit */
  47. int background_limit = BACKGROUND_TICS; /* background cycle limit */
  48.  
  49. char search_dir[65] = {SEARCH_DIR}; /* dir to search for spool files */
  50. volatile int   int_28_active = 0;    /* true if activated by INT 28 */
  51. volatile int   interval_timer;       /* for sleeping a number of tics */ 
  52.  
  53. /* old interrupt pointers are stored here */    
  54. INTVECT old_int8, old_int9, old_int10, old_int13;
  55. INTVECT old_int1B, old_int23, old_int24, old_int25;
  56. INTVECT old_int26, old_int28;
  57.  
  58. /* prototypes for this module */
  59. void main_loop();
  60. void interrupt far new_int8(INTERRUPT_REGS);
  61. void interrupt far new_int9(INTERRUPT_REGS);
  62. void interrupt far new_int10(void);
  63. void interrupt far new_int13(void);
  64. void interrupt far new_int1B(INTERRUPT_REGS);
  65. void interrupt far new_int23(INTERRUPT_REGS);
  66. void interrupt far new_int24(INTERRUPT_REGS);
  67. void interrupt far new_int25(void);
  68. void interrupt far new_int26(void);
  69. void interrupt far new_int28(INTERRUPT_REGS);
  70. int  spooler_active(void);
  71. int  search_spl_que(char * fname);
  72. void suspend_foreground(void);
  73. void suspend_background(void);
  74.  
  75. /* returns nonzero if PRINT installed */
  76. int spooler_active()
  77. {
  78.     union REGS  regs;
  79.  
  80.     regs.x.ax = 0x0100;         /* PRINT install check */
  81.     int86(0x2f,®s,®s);    /* call multiplex interrupt */
  82.     return(regs.h.al == 0xff);  /* FF if installed */
  83. }
  84.  
  85. /* returns nonzero if file is in the spooler queue */
  86. int search_spl_que(char * fname)
  87. {
  88.     union REGS  regs;
  89.     struct SREGS   sregs;
  90.     char far *  que_ptr;
  91.     char que_name[65];
  92.     int i;
  93.     int found = 0;
  94.  
  95.    if (spooler_active())
  96.    {
  97.       regs.x.ax = 0x0104;  /* get spooler status */
  98.       int86x(0x2f,®s,®s,&sregs);
  99.       /* on return from call DS:SI points to print queue */
  100.       FP_SEG(que_ptr) = sregs.ds;
  101.       FP_OFF(que_ptr) = regs.x.si;
  102.       /* release hold on spooler, side effect of status*/
  103.       regs.x.ax = 0x0105;
  104.       int86x(0x2f,®s,®s,&sregs);
  105.       while (*que_ptr && !found)  /* while items in queue */
  106.       {
  107.          for (i = 0; i < 65; i++)
  108.             que_name[i] = *(que_ptr + i);
  109.          if (found = !strcmpi(que_name,fname))
  110.              break;
  111.          que_ptr += 65;
  112.       }
  113.    }
  114.  
  115.    return(found);
  116. }
  117.  
  118. void main_loop()
  119. {
  120.     struct find_t c_file;
  121.     union REGS regs;
  122.     struct SREGS sregs;
  123.     struct prReq prRequest;
  124.     struct prReq far * ptr;
  125.  
  126.     while (1)
  127.     {   
  128.       strcpy(search_work,search_dir);
  129.       strcat(search_work,"*.SPL");   /* create dir search string */
  130.    
  131.       interval_timer = 18 * 30;     /* search every 30 seconds */
  132.       while (interval_timer)    /* wait between each dir search */
  133.           background_limit = BACKGROUND_YIELD;  /* yield for fgrnd */
  134.  
  135.       if (!_dos_findfirst(search_work,_A_NORMAL,&c_file))
  136.       {
  137.          /* if spooler installed, dos 3.xx+ and file size > 0 */
  138.          if (spooler_active() && _osmajor >= 3 && c_file.size)
  139.          {
  140.            strcpy(search_work,search_dir);
  141.            strcat(search_work,c_file.name); /* full pathname */
  142.            prRequest.level = 0;
  143.            prRequest.fname = search_work;
  144.            regs.x.ax = 0x0101;
  145.            ptr = &prRequest;
  146.            sregs.ds = FP_SEG(ptr);
  147.            regs.x.dx= FP_OFF(ptr);
  148.            int86x(0x2f,®s,®s,&sregs);
  149.  
  150.            while (search_spl_que(search_work))  /* wait till done */
  151.            {
  152.                interval_timer = 18 * 30;  /* sleep for 30 seconds */
  153.                while (interval_timer)
  154.                    background_limit = BACKGROUND_YIELD;
  155.            }
  156.  
  157.            unlink(search_work);     /* delete file */
  158.            background_limit = BACKGROUND_YIELD;
  159.         }
  160.       }
  161.    }
  162. }
  163.  
  164. union REGS regs;
  165. struct SREGS sregs;
  166.  
  167. void suspend_foreground()
  168. {
  169.     /* SWAP TO BACKGROUND */
  170.     tic_count = 0;
  171.     /* save old handlers */
  172.     old_int1B= _dos_getvect(0x1B); 
  173.     old_int23= _dos_getvect(0x23); 
  174.     old_int24= _dos_getvect(0x24); 
  175.  
  176.     /* set our interrupt handlers */
  177.     _dos_setvect(0x1b,new_int1B);
  178.     _dos_setvect(0x23,new_int23);
  179.     _dos_setvect(0x24,new_int24);
  180.  
  181.     /* save current PSP and set to ours */
  182.     foreground_psp = GetPSP();
  183.     SetPSP(my_psp);
  184.  
  185.     /* get foreground DTA */
  186.     regs.h.ah = GET_DTA;
  187.     intdosx(®s, ®s, &sregs); 
  188.     foreground_dta_seg = sregs.es;
  189.     foreground_dta_off = regs.x.bx;
  190.  
  191.     /* set up our DTA */
  192.     regs.h.ah = SET_DTA;
  193.     regs.x.dx = 0x80;   /* use default in PSP area */
  194.     sregs.ds = my_psp;
  195.     intdosx(®s, ®s, &sregs); 
  196.  
  197.     /* save error info */
  198.     GetExtErr(&foreground_ErrInfo);
  199.  
  200.     if (! first_time)
  201.         SetExtErr(&my_ErrInfo);
  202.  
  203.     in_progress = 1;
  204.     background_limit = BACKGROUND_TICS; /* set default limit */
  205. }
  206.  
  207. void suspend_background()
  208. {
  209.     /* SWAP TO FOREGROUND */
  210.  
  211.     /* put back original DTA */
  212.     regs.h.ah = SET_DTA;
  213.     regs.x.dx = foreground_dta_off; 
  214.     sregs.ds  = foreground_dta_seg;
  215.     intdosx(®s, ®s, &sregs); 
  216.  
  217.     /* put back original PSP */
  218.     SetPSP(foreground_psp);
  219.  
  220.     /* put back original INTS */
  221.     _dos_setvect(0x1b,old_int1B);
  222.     _dos_setvect(0x23,old_int23);
  223.     _dos_setvect(0x24,old_int24);
  224.  
  225.     /* get error info */
  226.     GetExtErr(&my_ErrInfo);
  227.     SetExtErr(&foreground_ErrInfo);
  228.  
  229.     tic_count = 0;  
  230.     in_progress = 0;
  231.     int_28_active = 0;
  232.     foreground_limit = FOREGROUND_TICS; /* set default limit */
  233. }
  234.  
  235. /**********
  236. * TIMER TICK INTERRUPT HANDLER
  237. **********/
  238. void interrupt far new_int8(INTERRUPT_REGS r)
  239. {
  240.     tic_count++;
  241.     
  242.     if (interval_timer)
  243.         interval_timer--;
  244.  
  245.     if ((in_progress && (tic_count >= background_limit) &&  
  246.        !DosBusy() && !unsafe_flag) || 
  247.        (in_progress && int_28_active && !Int28DosBusy() && 
  248.            (tic_count >=background_limit)))
  249.     {
  250.       suspend_background();
  251.       restore_stack();
  252.     }
  253.     else if ((!in_progress && (tic_count >= foreground_limit) &&
  254.         !DosBusy() && !unsafe_flag) ||
  255.        (!in_progress && int_28_active && !Int28DosBusy() && 
  256.            (tic_count >=foreground_limit)))
  257.     {
  258.       set_stack();
  259.       suspend_foreground();
  260.       if (first_time)
  261.       {
  262.          first_time = 0;
  263.          timer_int_chain();
  264.       }
  265.     }
  266.    old_int8();    /* call old handler */
  267.  
  268. /**********
  269. * KEYBOARD INTERRUPT HANDLER
  270. **********/
  271. void interrupt far new_int9(INTERRUPT_REGS r)
  272. {
  273.    unsafe_flag++;
  274.    old_int9();     
  275.    if (in_progress)
  276.       background_limit = BACKGROUND_YIELD; /* set to swap to fgrnd */  
  277.    foreground_limit = 18;               /* since user hit keyboard */
  278.    unsafe_flag--;
  279.  
  280. /*********
  281. * CTRL-BREAK INTERRUPT HANDLER
  282. *********/
  283. void interrupt far new_int1B(INTERRUPT_REGS r)
  284. {
  285.     /* do nothing */
  286.                   
  287. /**********
  288. * CTRL-C INTERRUPT HANDLER
  289. **********/
  290. void interrupt far new_int23(INTERRUPT_REGS r)
  291. {
  292.     /* do nothing */
  293.  
  294. /**********
  295. * CRTITICAL ERROR INTERRUPT HANDLER
  296. **********/
  297. void interrupt far new_int24(INTERRUPT_REGS r)
  298. {
  299.     if (_osmajor >= 3)
  300.         r.ax = 3;   /* fail dos function */
  301.     else
  302.         r.ax = 0;        
  303.  
  304. /**********
  305. * DOS IDLE INTERRUPT HANDLER
  306. **********/
  307. void interrupt far new_int28(INTERRUPT_REGS r)
  308. {
  309.     if (!in_progress && !Int28DosBusy() && !unsafe_flag && 
  310.         tic_count > foreground_limit)
  311.     {
  312.       foreground_limit = FOREGROUND_YIELD;   /* stop foreground */
  313.       int_28_active = 1;      
  314.       _enable();              /* STI */
  315.       while (int_28_active)
  316.           ;        /*spin waiting for task swap to bckgrnd*/
  317.     }
  318.    (*old_int28)();    /* call old handler */
  319.  
  320. main()
  321. {
  322.     unsigned        memtop;
  323.     unsigned        dummy;
  324.     void far* far*  tmpptr;
  325.  
  326.     puts("Multi-Tasking PRINT spooler installing");
  327.  
  328.     if (_osmajor < 3)
  329.     {
  330.         puts("Error: MS-DOS version 3.00 or greater required");
  331.         exit(1);
  332.     }
  333.  
  334.     if (! spooler_active())
  335.         puts("Warning: Print Spooler not active");
  336.  
  337.     InitInDos();
  338.     my_psp = GetPSP();
  339.  
  340.     /* MALLOC a stack for our TSR section */ 
  341.     stack_ptr = malloc(STACK_SIZE);      
  342.     stack_ptr += STACK_SIZE;
  343.  
  344.     ptr = stack_ptr;
  345.     *(--stack_ptr) = 0xF2;  /* set up stack as if an an IRET was done*/
  346.     *(--stack_ptr) = 0x02;
  347.     stack_ptr -= 4;
  348.     tmpptr = stack_ptr;
  349.     *(tmpptr) = main_loop;
  350.  
  351.     /* get interrupt vectors */
  352.     old_int8  = _dos_getvect(0x08); /* timer int */
  353.     old_int9  = _dos_getvect(0x09); /* keyboard int */
  354.     old_int10 = _dos_getvect(0x10); /* video int */
  355.     old_int13 = _dos_getvect(0x13); /* disk int */
  356.     old_int25 = _dos_getvect(0x25); /* sector read int */
  357.     old_int26 = _dos_getvect(0x26); /* sector write int */
  358.     old_int28 = _dos_getvect(0x28); /* dos idle int */
  359.  
  360.     init_intr();    /* init asm variables */ 
  361.  
  362.     _dos_setvect(0x08,new_int8); 
  363.     _dos_setvect(0x09,new_int9); 
  364.     _dos_setvect(0x10,new_int10); 
  365.     _dos_setvect(0x13,new_int13); 
  366.     _dos_setvect(0x25,new_int25); 
  367.     _dos_setvect(0x26,new_int26); 
  368.     _dos_setvect(0x28,new_int28); 
  369.  
  370. #define PARAGRAPHS(x)   ((FP_OFF(x) + 15) >> 4)
  371.  
  372.     /* release unused heap to MS-DOS */
  373.     /* All MALLOCS for TSR section must be done in TSR_INIT() */
  374.     /* calculate top of memory, shrink block, and go TSR */
  375.     segread(&sregs);    
  376.     memtop = sregs.ds + PARAGRAPHS(ptr) - _psp;
  377.     
  378.     _dos_setblock(memtop, _psp, &dummy);
  379.     _dos_keep(0, memtop);
  380. }
  381.  
  382.