home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / locking.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  8KB  |  258 lines

  1. /***
  2. *locking.c - file locking function
  3. *
  4. *       Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       Defined the _locking() function - file locking and unlocking
  8. *
  9. *******************************************************************************/
  10.  
  11. #ifndef _MAC
  12.  
  13.  
  14. #include <cruntime.h>
  15. #include <oscalls.h>
  16. #include <errno.h>
  17. #include <sys\locking.h>
  18. #include <io.h>
  19. #include <stdlib.h>
  20. #include <internal.h>
  21. #include <msdos.h>
  22. #include <mtdll.h>
  23.  
  24. /***
  25. *int _locking(fh,lmode,nbytes) - file record locking function
  26. *
  27. *Purpose:
  28. *       Locks or unlocks nbytes of a specified file
  29. *
  30. *       Multi-thread - Must lock/unlock the file handle to prevent
  31. *       other threads from working on the file at the same time as us.
  32. *       [NOTE: We do NOT release the lock during the 1 second delays
  33. *       since some other thread could get in and do something to the
  34. *       file.  The DOSFILELOCK call locks out other processes, not
  35. *       threads, so there is no multi-thread deadlock at the DOS file
  36. *       locking level.]
  37. *
  38. *Entry:
  39. *       int fh -        file handle
  40. *       int lmode -     locking mode:
  41. *                           _LK_LOCK/_LK_RLCK -> lock, retry 10 times
  42. *                           _LK_NBLCK/_LK_N_BRLCK -> lock, don't retry
  43. *                           _LK_UNLCK -> unlock
  44. *       long nbytes -   number of bytes to lock/unlock
  45. *
  46. *Exit:
  47. *       returns 0 if successful
  48. *       returns -1 and sets errno if unsuccessful
  49. *
  50. *Exceptions:
  51. *
  52. *******************************************************************************/
  53.  
  54. int __cdecl _locking (
  55.         int fh,
  56.         int lmode,
  57.         long nbytes
  58.         )
  59. {
  60.         ULONG dosretval;                /* o.s. return code */
  61.         LONG lockoffset;
  62.         int retry;                      /* retry count */
  63.  
  64.         /* validate file handle */
  65.         if ( ((unsigned)fh >= (unsigned)_nhandle) ||
  66.              !(_osfile(fh) & FOPEN) )
  67.         {
  68.                 /* fh out of range */
  69.                 errno = EBADF;
  70.                 _doserrno = 0;  /* not an o.s. error */
  71.                 return -1;
  72.         }
  73.  
  74.         _lock_fh(fh);                   /* acquire file handle lock */
  75.  
  76.         /* obtain current position in file by calling _lseek */
  77.         /* Use _lseek_lk as we already own lock */
  78.         lockoffset = _lseek_lk(fh, 0L, 1);
  79.         if (lockoffset == -1) {
  80.                 _unlock_fh(fh);
  81.                 return -1;
  82.         }
  83.  
  84.  
  85.         /* set retry count based on mode */
  86.         if (lmode == _LK_LOCK || lmode == _LK_RLCK)
  87.                 retry = 9;              /* retry 9 times */
  88.         else
  89.                 retry = 0;              /* don't retry */
  90.  
  91.         /* ask o.s. to lock the file until success or retry count finished */
  92.         /* note that the only error possible is a locking violation, since */
  93.         /* an invalid handle would have already failed above */
  94.         for (;;) {
  95.  
  96.                 dosretval = 0;
  97.                 if (lmode == _LK_UNLCK) {
  98.                     if ( !(UnlockFile((HANDLE)_get_osfhandle(fh),
  99.                                       lockoffset,
  100.                                       0L,
  101.                                       nbytes,
  102.                                       0L))
  103.                        )
  104.                         dosretval = GetLastError();
  105.  
  106.                 } else {
  107.                     if ( !(LockFile((HANDLE)_get_osfhandle(fh),
  108.                                     lockoffset,
  109.                                     0L,
  110.                                     nbytes,
  111.                                     0L))
  112.                        )
  113.                         dosretval = GetLastError();
  114.                 }
  115.  
  116.                 if (retry <= 0 || dosretval == 0)
  117.                         break;  /* exit loop on success or retry exhausted */
  118.  
  119.                 Sleep(1000L);
  120.  
  121.                 --retry;
  122.         }
  123.  
  124.         _unlock_fh(fh);                 /* release the file handle lock */
  125.  
  126.         if (dosretval != 0) {
  127.                 /* o.s. error occurred -- file was already locked; if a
  128.                    blocking call, then return EDEADLOCK, otherwise map
  129.                    error normally */
  130.                 if (lmode == _LK_LOCK || lmode == _LK_RLCK) {
  131.                         errno = EDEADLOCK;
  132.                         _doserrno = dosretval;
  133.                 }
  134.                 else {
  135.                         _dosmaperr(dosretval);
  136.                 }
  137.                 return -1;
  138.         }
  139.         else
  140.                 return 0;
  141. }
  142.  
  143.  
  144. #else  /* _MAC */
  145.  
  146.  
  147. #include <cruntime.h>
  148. #include <errno.h>
  149. #include <sys\locking.h>
  150. #include <io.h>
  151. #include <stdlib.h>
  152. #include <internal.h>
  153. #include <memory.h>
  154. #include <msdos.h>
  155. #include <macos\files.h>
  156. #include <macos\errors.h>
  157.  
  158. #include <stdio.h>
  159.  
  160. /***
  161. *int _locking(fh,lmode,nbytes) - file record locking function
  162. *
  163. *Purpose:
  164. *       Locks or unlocks nbytes of a specified file
  165. *
  166. *
  167. *Entry:
  168. *       int fh -        file handle
  169. *       int lmode -     locking mode:
  170. *                           _LK_LOCK/_LK_RLCK -> not supported
  171. *                           _LK_NBLCK/_LK_N_BRLCK -> lock, don't retry
  172. *                           _LK_UNLCK -> unlock
  173. *       long nbytes -   number of bytes to lock/unlock
  174. *
  175. *Exit:
  176. *       returns 0 if successful
  177. *       returns -1 and sets errno if unsuccessful
  178. *
  179. *Exceptions:
  180. *
  181. *******************************************************************************/
  182.  
  183. int __cdecl _locking (
  184.         int fh,
  185.         int lmode,
  186.         long nbytes
  187.         )
  188. {
  189.         ParamBlockRec param;
  190.         OSErr osErr;
  191.  
  192.         /* validate file handle */
  193.         if ((unsigned)fh >= (unsigned)_nfile || !(_osfile[fh] & FOPEN)) {
  194.                 /* fh out of range */
  195.                 errno = EBADF;
  196.                 _macerrno = 0;
  197.                 return -1;
  198.         }
  199.  
  200.         memset(¶m, 0, sizeof(ParamBlockRec));
  201.         param.ioParam.ioRefNum = _osfhnd[fh];
  202.         param.ioParam.ioReqCount =      nbytes;
  203.         param.ioParam.ioPosMode = fsAtMark;
  204.         param.ioParam.ioPosOffset = 0;
  205.  
  206.         switch (lmode)
  207.         {
  208.                 case LK_UNLCK:
  209.                         if (_osfile[fh] & FLOCK)
  210.                         {
  211.                                 osErr = PBUnlockRangeSync(¶m);
  212.                         }
  213.                         else
  214.                         {
  215.                                 errno = EACCES;
  216.                                 return -1;
  217.                         }
  218.                         break;
  219.  
  220.                 case _LK_NBLCK:
  221.                 case  LK_NBRLCK:
  222.                         osErr = PBLockRangeSync(¶m);
  223.  
  224.                         /* If this fh hasn't been locked before test the    */
  225.                         /* lock. This test is needed because the Mac will   */
  226.                         /* not lock local files but it will not return an   */
  227.                         /* error                                            */
  228.                         if (osErr == 0  && !(_osfile[fh] & FLOCK))
  229.                         {
  230.                             /* If lock took this should error */
  231.                             if (PBLockRangeSync(¶m))
  232.                                 {
  233.                                         _osfile[fh] |= FLOCK;
  234.                                 }
  235.                                 else
  236.                                 {
  237.                                         errno = EINVAL;
  238.                                         return -1;
  239.                                 }
  240.                         }
  241.                         break;
  242.  
  243.                 default:
  244.                         errno = EINVAL;
  245.                         return -1;
  246.         }
  247.  
  248.         if (osErr)
  249.         {
  250.                 _dosmaperr(osErr);
  251.                 return -1;
  252.         }
  253.         return 0;
  254. }
  255.  
  256.  
  257. #endif  /* _MAC */
  258.