aioPxLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:50k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* aioPxLib.c - asynchronous I/O (AIO) library (POSIX) */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01k,17jul00,jgn  merge DOT-4 pthreads changes
  8. 01j,26sep01,jgn  disable manual generation for aio_fsync (SPR #34282)
  9. 01i,04feb99,vcm  adding errno code for aio_return()
  10. 01h,15jan95,rhp  fix typo.
  11.             jdi  doc cleanup.
  12. 01g,08apr94,kdl  changed aio_show() reference to aioShow().
  13. 01f,01feb94,dvs  documentation changes.
  14. 01e,26jan94,kdl  commented out aio_fsync().
  15. 01d,21jan94,kdl  minor doc cleanup; made driver-related routines NOMANUAL.
  16. 01c,12jan94,kdl  changed aioInit() to aioPxLibInit(); added include of 
  17.  private/schedP.h; general cleanup.
  18. 01b,06dec93,dvs  minor configuration related changes; changed S_aioLib* to 
  19.  S_aioPxLib*
  20. 01a,04apr93,elh  written.
  21. */
  22. /* 
  23. DESCRIPTION
  24. This library implements asynchronous I/O (AIO) according to the definition 
  25. given by the POSIX standard 1003.1b (formerly 1003.4, Draft 14).  AIO 
  26. provides the ability to overlap application processing and I/O operations 
  27. initiated by the application.  With AIO, a task can perform I/O simultaneously 
  28. to a single file multiple times or to multiple files.
  29. After an AIO operation has been initiated, the AIO proceeds in 
  30. logical parallel with the processing done by the application.
  31. The effect of issuing an asynchronous I/O request is as if a separate
  32. thread of execution were performing the requested I/O.
  33.  
  34. AIO LIBRARY
  35. The AIO library is initialized by calling aioPxLibInit(), which
  36. should be called once (typically at system start-up) after the I/O system 
  37. has already been initialized.
  38. AIO COMMANDS 
  39. The file to be accessed asynchronously is opened via the standard open 
  40. call.  Open returns a file descriptor which is used in subsequent AIO 
  41. calls.
  42.  
  43. The caller initiates asynchronous I/O via one of the following routines: 
  44. .IP aio_read() 15
  45. initiates an asynchronous read
  46. .IP aio_write()
  47. initiates an asynchronous write
  48. .IP lio_listio()
  49. initiates a list of asynchronous I/O requests
  50. .LP
  51. Each of these routines has a return value and error value 
  52. associated with it; however, these values indicate only whether the AIO 
  53. request was successfully submitted (queued), not the ultimate success or
  54. failure of the AIO operation itself.  
  55. There are separate return and error values associated with the success or
  56. failure of the AIO operation itself.  The error status can be retrieved
  57. using aio_error(); however, until the AIO operation completes, the error
  58. status will be EINPROGRESS.  After the AIO operation completes, the return
  59. status can be retrieved with aio_return().
  60. The aio_cancel() call cancels a previously submitted AIO request.  The
  61. aio_suspend() call waits for an AIO operation to complete.
  62. Finally, the aioShow() call (not a standard POSIX function) displays
  63. outstanding AIO requests.
  64. AIO CONTROL BLOCK
  65. Each of the calls described above takes an AIO control block (`aiocb') as
  66. an argument.  The calling routine must allocate space for the `aiocb', and
  67. this space must remain available for the duration of the AIO operation.
  68. (Thus the `aiocb' must not be created on the task's stack unless the
  69. calling routine will not return until after the AIO operation is complete
  70. and aio_return() has been called.)  Each `aiocb' describes a single AIO
  71. operation.  Therefore, simultaneous asynchronous I/O operations using the
  72. same `aiocb' are not valid and produce undefined results.
  73. The `aiocb' structure and the data buffers referenced by it are used 
  74. by the system to perform the AIO request.  Therefore, once the `aiocb' has
  75. been submitted to the system, the application must not modify the `aiocb' 
  76. structure until after a subsequent call to aio_return().  The aio_return() 
  77. call retrieves the previously submitted AIO data structures from the system.
  78. After the aio_return() call, the calling application can modify the
  79. `aiocb', free the memory it occupies, or reuse it for another AIO call. 
  80. As a result, if space for the `aiocb' is allocated off the stack 
  81. the task should not be deleted (or complete running) until the `aiocb' 
  82. has been retrieved from the system via an aio_return().
  83. The `aiocb' is defined in aio.h.  It has the following elements:
  84. .CS 
  85. struct
  86.          {
  87.          int                 aio_fildes;  
  88.          off_t               aio_offset; 
  89.          volatile void *     aio_buf; 
  90.          size_t              aio_nbytes;
  91.          int                 aio_reqprio;
  92.          struct sigevent     aio_sigevent;
  93.          int                 aio_lio_opcode;
  94.          AIO_SYS             aio_sys; 
  95.          } aiocb
  96. .CE 
  97. .IP `aio_fildes'
  98. file descriptor for I/O.
  99. .IP `aio_offset'
  100. offset from the beginning of the file where the
  101. AIO takes place.  Note that performing AIO on the file does not 
  102. cause the offset location to automatically increase as in read and write;
  103. the caller must therefore keep track of the location of reads and writes made 
  104. to the file (see POSIX COMPLIANCE below). 
  105. .IP `aio_buf'
  106. address of the buffer from/to which AIO is requested.
  107. .IP `aio_nbytes'
  108. number of bytes to read or write.
  109. .IP `aio_reqprio'
  110. amount by which to lower the priority of an AIO request.  Each
  111. AIO request is assigned a priority; this priority, based on the calling
  112. task's priority, indicates the desired order of execution relative to
  113. other AIO requests for the file.  The `aio_reqprio' member allows the
  114. caller to lower (but not raise) the AIO operation priority by the
  115. specified value.  Valid values for `aio_reqprio' are in the range of zero
  116. through AIO_PRIO_DELTA_MAX.  If the value specified by `aio_req_prio'
  117. results in a priority lower than the lowest possible task priority, the
  118. lowest valid task priority is used.
  119. .IP `aio_sigevent'
  120. (optional) if nonzero, the signal to return on completion of an operation.
  121. .IP `aio_lio_opcode'
  122. operation to be performed by a lio_listio() call; valid entries include
  123. LIO_READ, LIO_WRITE, and LIO_NOP.  
  124. .IP `aio_sys'
  125. a Wind River Systems addition to the `aiocb' structure; it is
  126. used internally by the system and must not be modified by the user.
  127. .LP
  128. EXAMPLES
  129. A writer could be implemented as follows:
  130. .CS
  131.     if ((pAioWrite = calloc (1, sizeof (struct aiocb))) == NULL)
  132.         {
  133.         printf ("calloc faileden");
  134.         return (ERROR);
  135.         }
  136.     pAioWrite->aio_fildes = fd;
  137.     pAioWrite->aio_buf = buffer;
  138.     pAioWrite->aio_offset = 0;
  139.     strcpy (pAioWrite->aio_buf, "test string");
  140.     pAioWrite->aio_nbytes  = strlen ("test string");
  141.     pAioWrite->aio_sigevent.sigev_notify = SIGEV_NONE;
  142.     aio_write (pAioWrite);
  143.     /@  .
  144. .
  145. do other work
  146. .
  147. .
  148.     @/
  149.     /@ now wait until I/O finishes @/
  150.     while (aio_error (pAioWrite) == EINPROGRESS)
  151.         taskDelay (1);
  152.     aio_return (pAioWrite);
  153.     free (pAioWrite);
  154. .CE
  155.    
  156. A reader could be implemented as follows:
  157. .CS
  158.     /@ initialize signal handler @/
  159.  
  160.     action1.sa_sigaction = sigHandler;
  161.     action1.sa_flags   = SA_SIGINFO;
  162.     sigemptyset(&action1.sa_mask);
  163.     sigaction (TEST_RT_SIG1, &action1, NULL);
  164.     if ((pAioRead = calloc (1, sizeof (struct aiocb))) == NULL)
  165.         {
  166.         printf ("calloc faileden");
  167.         return (ERROR);
  168.         }
  169.  
  170.     pAioRead->aio_fildes = fd;
  171.     pAioRead->aio_buf = buffer;
  172.     pAioRead->aio_nbytes = BUF_SIZE;
  173.     pAioRead->aio_sigevent.sigev_signo = TEST_RT_SIG1;
  174.     pAioRead->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
  175.     pAioRead->aio_sigevent.sigev_value.sival_ptr = (void *)pAioRead;
  176.  
  177.     aio_read (pAioRead);
  178.     /@
  179.         .
  180.         .
  181.         do other work 
  182. .
  183. .
  184.     @/
  185. .CE
  186. The signal handler might look like the following:
  187. .CS
  188. void sigHandler
  189.     (
  190.     int                 sig,
  191.     struct siginfo      info,
  192.     void *              pContext
  193.     )
  194.     {
  195.     struct aiocb *      pAioDone;
  196.     pAioDone = (struct aiocb *) info.si_value.sival_ptr;
  197.     aio_return (pAioDone);
  198.     free (pAioDone);
  199.     }
  200. .CE
  201. POSIX COMPLIANCE
  202. Currently VxWorks does not support the O_APPEND flag in the open call.  
  203. Therefore, the user must keep track of the offset in the file that 
  204. the asynchronous writes occur (as in the case of reads).  The `aio_offset'
  205. field is used to specify that file position.
  206. In addition, VxWorks does not currently support synchronized I/O.
  207. INCLUDE FILES: aio.h
  208. SEE ALSO: POSIX 1003.1b document
  209. INTERNAL
  210. As it currently stands, aioLib could be better integrated into the I/O 
  211. system.  aioDrvTable and aioFdTable could be integrated with drvTable and 
  212. fdTable respectively.  Also, the hook routines aioFdNew and aioFdFree
  213. could be eliminated.  However we choose not to do this (for now) to
  214. avoid increasing the size of the I/O structures (thus causing the user
  215. to have to recompile their applications).  This should be changed  
  216. later.
  217. Although the interface between aioLib and AIO drivers has been defined, 
  218. currently there is only support to use it with the AIO system driver.  Work
  219. needs to be done (as well as modifications to the xxxFsLib and scsiLib) 
  220. before it can be implemented in our block devices.
  221. */ 
  222. /* includes */ 
  223. #include "vxWorks.h" 
  224. #include "aio.h"
  225. #include "private/iosLibP.h" 
  226. #include "string.h"
  227. #include "qFifoLib.h"
  228. #include "timers.h"
  229. #include "intLib.h"
  230. #include "taskLib.h"
  231. #include "stdlib.h"
  232. #include "tickLib.h"
  233. #include "private/mutexPxLibP.h"
  234. #include "private/schedP.h" 
  235. #define __PTHREAD_SRC
  236. #include "pthread.h"
  237. /* defines */
  238. #define AIO_LOCK() (semTake (&aioSem, WAIT_FOREVER))
  239. #define AIO_UNLOCK() (semGive (&aioSem))
  240. /* typedefs */
  241. typedef struct  /* each parameter */
  242.     {
  243.     AIO_DEV *  pDev; /* device */
  244.     int retVal; /* return value */
  245.     int errorVal; /* error value */
  246.     FUNCPTR syncRtn; /* sync routine */
  247.     } ARGS;
  248. /* globals */
  249. FUNCPTR aioPrintRtn = NULL;
  250. /* locals */
  251. LOCAL AIO_DRV_ENTRY * aioDrvTable = NULL; /* driver table */
  252. LOCAL AIO_FD_ENTRY * aioFdTable = NULL; /* fd table */
  253. LOCAL AIO_CLUST * aioClustTable = NULL; /* cluster table */
  254. LOCAL int aioClustMax; /* max clusters */
  255. LOCAL SEMAPHORE aioSem; /* AIO semaphore */
  256. /* forward declarations */
  257. LOCAL STATUS  aioSubmit (struct aiocb * pAiocb, int op, AIO_CLUST * pClust);
  258. LOCAL int     aioListEach (struct aiocb * list[], int num, FUNCPTR routine, 
  259.    int arg1, int arg2);
  260. LOCAL BOOL    aioListSubmit (struct aiocb * pAiocb, AIO_CLUST * pClust, 
  261.      BOOL * pFailed);
  262. LOCAL BOOL    aioListClust (struct aiocb * pAiocb, AIO_CLUST * pClust, 
  263.     int bogus);
  264. LOCAL BOOL    aioListError (struct aiocb * pAiocb, int * pError, int bogus);
  265. LOCAL BOOL    aioListWait (struct aiocb * pAiocb, AIO_WAIT_ID * pAioId, 
  266.     int bogus);
  267. LOCAL BOOL    aioListUnwait (struct aiocb * pAiocb, AIO_WAIT_ID * pAioId, 
  268.      int bogus);
  269. LOCAL STATUS  aioSyncNode (DL_NODE * pFdNode, ARGS * pArgs);
  270. LOCAL void    aioClustRet (struct aiocb * pAiocb, AIO_CLUST * pClust);
  271. LOCAL AIO_CLUST *    aioClustGet (void);
  272. /* I/O hook routines */
  273. LOCAL void    aioFdFree (int fd);
  274. LOCAL void    aioFdNew (int fd);
  275. extern BOOL iosLibInitialized;
  276. /*******************************************************************************
  277. * aioPxLibInit - initialize the asynchronous I/O (AIO) library
  278. *
  279. * This routine initializes the AIO library.  It should be called only
  280. * once after the I/O system has been initialized.  <lioMax> specifies the 
  281. * maximum number of outstanding lio_listio() calls at one time.  If <lioMax>
  282. * is zero, the default value of AIO_CLUST_MAX is used.
  283. *
  284. * RETURNS: OK if successful, otherwise ERROR.
  285. *
  286. * ERRNO: S_aioPxLib_IOS_NOT_INITIALIZED
  287. *
  288. * INTERNAL:  This library relies on the fact that the IOS library 
  289. * has been installed because it uses the variables maxDrivers and maxFiles. 
  290. * This can be better integrated into the I/O system but for now we do this 
  291. * to avoid adding entries to the drvTable and fdTable.
  292. */
  293. STATUS aioPxLibInit 
  294.     (
  295.     int lioMax  /* max outstanding lio calls */
  296.     )
  297.     {
  298.     int ix; /* index */
  299.     if (!iosLibInitialized)
  300. {
  301. errno = S_aioPxLib_IOS_NOT_INITIALIZED;
  302. return (ERROR); /* ios not initialized */
  303. }
  304.     if (aioDrvTable != NULL)
  305. return (OK); /* already initialized */
  306.     /* Allocate memory for the AIO driver table */
  307.     if ((aioDrvTable = calloc (maxDrivers, sizeof (AIO_DRV_ENTRY))) == NULL)
  308. return (ERROR);
  309.     /* Allocate memory for the AIO fd table */
  310.     if ((aioFdTable = calloc (maxFiles, sizeof (AIO_FD_ENTRY))) == NULL)
  311. return (ERROR);
  312.     for (ix = 0; ix < maxFiles; ix++)
  313. {
  314. AIO_FD_ENTRY * pEntry = &aioFdTable [ix];
  315.         pEntry->pFdEntry = &fdTable [ix];
  316.         semMInit (&pEntry->ioQSem, SEM_DELETE_SAFE | SEM_Q_PRIORITY);
  317. }
  318.     /* Allocate and initialize the cluster table */
  319.     aioClustMax = (lioMax == 0) ? AIO_CLUST_MAX : lioMax;
  320.     if ((aioClustTable = calloc (aioClustMax, sizeof (AIO_CLUST))) == NULL)
  321. return (ERROR); /* memory problem */ 
  322.     for (ix = 0 ; ix < aioClustMax; ix++)
  323. aioClustTable [ix].inuse = FALSE;
  324.     /* Initialize semaphore that protects data structures created above */
  325.     semMInit (&aioSem, SEM_DELETE_SAFE | SEM_Q_PRIORITY);
  326.     /* Hook into the ios system */ 
  327.     iosFdNewHookRtn  = aioFdNew;
  328.     iosFdFreeHookRtn = aioFdFree;
  329.     return (OK);
  330.     }
  331. /* POSIX specified routines */
  332. /*******************************************************************************
  333. *
  334. * aio_read - initiate an asynchronous read (POSIX)
  335. *
  336. * This routine asynchronously reads data based on the following parameters
  337. * specified by members of the AIO control structure <pAiocb>.  It reads
  338. * `aio_nbytes' bytes of data from the file `aio_fildes' into the buffer
  339. * `aio_buf'.
  340. *
  341. * The requested operation takes place at the absolute position in the file
  342. * as specified by `aio_offset'.
  343. *
  344. * `aio_reqprio' can be used to lower the priority of the AIO request; if
  345. * this parameter is nonzero, the priority of the AIO request is
  346. * `aio_reqprio' lower than the calling task priority.
  347. *
  348. * The call returns when the read request has been initiated or queued to the
  349. * device.  aio_error() can be used to determine the error status and of the
  350. * AIO operation.  On completion, aio_return() can be used to determine the
  351. * return status.
  352. *
  353. * `aio_sigevent' defines the signal to be generated on completion 
  354. * of the read request.  If this value is zero, no signal is generated. 
  355. *
  356. * RETURNS: OK if the read queued successfully, otherwise ERROR.
  357. *
  358. * ERRNO: EBADF, EINVAL
  359. *
  360. * INCLUDE FILES: aio.h
  361. *
  362. * SEE ALSO: aio_error(), aio_return(), read()
  363. *
  364. */
  365. int aio_read 
  366.     (
  367.     struct aiocb *  pAiocb /* AIO control block */
  368.     )
  369.     {
  370.     return (aioSubmit (pAiocb, IO_READ, NULL));
  371.     }
  372.     
  373. /*******************************************************************************
  374. *
  375. * aio_write - initiate an asynchronous write (POSIX)
  376. *
  377. * This routine asynchronously writes data based on the following parameters
  378. * specified by members of the AIO control structure <pAiocb>.  It writes
  379. * `aio_nbytes' of data to the file `aio_fildes' from the buffer `aio_buf'.
  380. *
  381. * The requested operation takes place at the absolute position in the file
  382. * as specified by `aio_offset'.
  383. *
  384. * `aio_reqprio' can be used to lower the priority of the AIO request; if
  385. * this parameter is nonzero, the priority of the AIO request is
  386. * `aio_reqprio' lower than the calling task priority.
  387. *
  388. * The call returns when the write request has been initiated or queued to
  389. * the device.  aio_error() can be used to determine the error status and of
  390. * the AIO operation.  On completion, aio_return() can be used to determine
  391. * the return status.
  392. *
  393. * `aio_sigevent' defines the signal to be generated on completion 
  394. * of the write request.  If this value is zero, no signal is generated. 
  395. *
  396. * RETURNS: OK if write queued successfully, otherwise ERROR.
  397. *
  398. * ERRNO: EBADF, EINVAL
  399. *
  400. * INCLUDE FILES: aio.h
  401. *
  402. * SEE ALSO: aio_error(), aio_return(), write()
  403. *
  404. */
  405. int aio_write 
  406.     (
  407.     struct aiocb *  pAiocb  /* AIO control block */
  408.     )
  409.     {
  410.     return (aioSubmit (pAiocb, IO_WRITE, NULL));
  411.     }
  412. /*******************************************************************************
  413. *
  414. * lio_listio - initiate a list of asynchronous I/O requests (POSIX)
  415. *
  416. * This routine submits a number of I/O operations (up to AIO_LISTIO_MAX)
  417. * to be performed asynchronously.  <list> is a pointer to an array of 
  418. * `aiocb' structures that specify the AIO operations to be performed.  
  419. * The array is of size <nEnt>.   
  420. *
  421. * The `aio_lio_opcode' field of the `aiocb' structure specifies the AIO
  422. * operation to be performed.  Valid entries include LIO_READ, LIO_WRITE, and
  423. * LIO_NOP.  LIO_READ corresponds to a call to aio_read(), LIO_WRITE
  424. * corresponds to a call to aio_write(), and LIO_NOP is ignored.
  425. *
  426. * The <mode> argument can be either LIO_WAIT or LIO_NOWAIT.  If <mode> is 
  427. * LIO_WAIT, lio_listio() does not return until all the AIO operations 
  428. * complete and the <pSig> argument is ignored.  If <mode> is LIO_NOWAIT, the 
  429. * lio_listio() returns as soon as the operations are queued.  In this case, 
  430. * if <pSig> is not NULL and the signal number indicated by
  431. * `pSig->sigev_signo' is not zero, the signal `pSig->sigev_signo' is
  432. * delivered when all requests have completed.
  433. *
  434. * RETURNS: OK if requests queued successfully, otherwise ERROR.
  435. *
  436. * ERRNO: EINVAL, EAGAIN, EIO
  437. *
  438. * INCLUDE FILES: aio.h
  439. *
  440. * SEE ALSO: aio_read(), aio_write(), aio_error(), aio_return().
  441. */
  442. int lio_listio
  443.     (
  444.     int  mode, /* LIO_WAIT or LIO_NOWAIT */
  445.     struct aiocb *  list[], /* list of operations */
  446.     int  nEnt, /* size of list */
  447.     struct sigevent *  pSig /* signal on completion */
  448.     )
  449.     {
  450.     AIO_CLUST * pClust; /* cluster */
  451.     int errorVal = 0; /* error value */
  452.     STATUS retVal = OK; /* return value */
  453.     BOOL  submitFailed = FALSE; /* submit failed */
  454.     
  455.     /* Validate parameters */
  456.     if (((mode != LIO_WAIT) && (mode != LIO_NOWAIT)) || (nEnt > AIO_LISTIO_MAX))
  457. {
  458. errno = EINVAL;
  459. return (ERROR); /* invalid parameter */
  460. }
  461.     if ((pSig != NULL) && (pSig->sigev_notify == SIGEV_SIGNAL) &&
  462. ((pSig->sigev_signo < 1) || (pSig->sigev_signo > _NSIGS)))
  463. {
  464. errno = EINVAL;
  465.   return (ERROR); /* safety check */
  466. }
  467.     /* Obtain a free cluster */
  468.     if ((pClust = aioClustGet ()) == NULL)
  469. return (ERROR);  /* no clusters available  */
  470.     if ((mode == LIO_NOWAIT) && (pSig != NULL) &&
  471. (pSig->sigev_notify == SIGEV_SIGNAL))
  472. {
  473. sigPendInit (&pClust->sigpend);
  474. pClust->sigpend.sigp_info.si_signo = pSig->sigev_signo;
  475. pClust->sigpend.sigp_info.si_value = pSig->sigev_value;
  476. pClust->sigpend.sigp_info.si_code = SI_ASYNCIO;
  477. }
  478.     else
  479. pClust->sigpend.sigp_info.si_signo = 0;
  480.     /* Link up cluster and submit AIO requests */
  481.     aioListEach (list, nEnt, aioListClust, (int) pClust, 0);
  482.     aioListEach (list, nEnt, aioListSubmit, (int) pClust, (int) &submitFailed);
  483.     if (mode == LIO_NOWAIT)
  484. {
  485.      if (submitFailed)
  486.     {
  487.     errno = EIO;
  488.     return (ERROR); /* submit failed */
  489.     }
  490. else
  491.     return (OK); /* don't wait for I/O */
  492. }
  493.     /* Wait for I/O completion */
  494.     mutex_lock (&pClust->lock);
  495.     retVal = OK;
  496.     while ((pClust->refCnt > 0) && (retVal == OK)) 
  497. retVal = cond_timedwait (&pClust->wake, &pClust->lock, NULL);
  498.     mutex_unlock (&pClust->lock);
  499.     if (retVal != OK)
  500. {
  501. errno = retVal;
  502.      return (ERROR); /* signal */
  503. }
  504.     /* Check for I/O errors */
  505.     aioListEach (list, nEnt, aioListError, (int) &errorVal, 0);
  506.     if (errorVal)
  507.        {
  508.        errno = EIO;
  509.        return (ERROR); /* an AIO request failed */
  510.        }
  511.     return (OK); /* I/O completed successfully */
  512.     }
  513. /*******************************************************************************
  514. *
  515. * aio_suspend - wait for asynchronous I/O request(s)  (POSIX)
  516. *
  517. * This routine suspends the caller until one of the following occurs:
  518. * .iP
  519. * at least one of the previously submitted asynchronous I/O operations
  520. * referenced by <list> has completed,
  521. * .iP
  522. * a signal interrupts the function, or
  523. * .iP
  524. * the time interval specified by <timeout> has passed
  525. * (if <timeout> is not NULL).
  526. * .LP
  527. * RETURNS: OK if an AIO request completes, otherwise ERROR.
  528. *
  529. * ERRNO: EAGAIN, EINTR  
  530. *
  531. * INCLUDE FILES: aio.h
  532. *
  533. * INTERNAL:  We make the task safe from deletion so the (stack) variables 
  534. * that were added to the wait list don't get hosed.  This could have 
  535. * been implemented with taskDeleteHooks.
  536. */
  537. int aio_suspend 
  538.     (
  539.     const struct aiocb *  list[], /* AIO requests */
  540.     int  nEnt, /* number of requests */
  541.     const struct timespec *  timeout /* wait timeout */
  542.     )
  543.     {
  544.     AIO_WAIT_ID aioId; /* AIO Id */
  545.     int numDone; /* num completed */
  546.     STATUS retVal = OK; /* return value */
  547.     int savtype; /* saved cancellation type */
  548.     /* Initialize the wait structure */
  549.     bzero ((caddr_t) &aioId, sizeof (AIO_WAIT_ID));
  550.     aioId.done   = FALSE;
  551.     
  552.     /* Link into pthreads support code */
  553.     if (_func_pthread_setcanceltype != NULL)
  554. {
  555. _func_pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &savtype);
  556. }
  557.     mutex_init (&aioId.lock, NULL);
  558.     cond_init (&aioId.wake, NULL);
  559.     taskSafe (); /* TASK_SAFE */
  560.     
  561.     /* Submit wait requests */
  562.     numDone = aioListEach ((struct aiocb **) list, nEnt, aioListWait, 
  563.    (int) &aioId, 0);
  564.     if (numDone == nEnt)
  565. {
  566. /* All wait requests got submitted - wait for one to complete */
  567.         mutex_lock (&aioId.lock);
  568. retVal = OK;
  569.      while ((!aioId.done) && (retVal == OK))
  570.     retVal = cond_timedwait (&aioId.wake, &aioId.lock, timeout); 
  571.         mutex_unlock (&aioId.lock);
  572. }
  573.     else
  574. {
  575. /* Wait requests didn't all get submited */
  576. if (errno != AIO_COMPLETED) /* not completed successfully */
  577.     retVal = errno;
  578. numDone = nEnt; /* cancel to the one failed */
  579.     }
  580.     /* Cancel outstanding wait requests */
  581.     aioListEach ((struct aiocb **) list, numDone, aioListUnwait, (int) &aioId, 
  582.  0);
  583.     taskUnsafe (); /* TASK_UNSAFE */
  584.     /* Link into pthreads support code */
  585.     if (_func_pthread_setcanceltype != NULL)
  586.         {
  587.         _func_pthread_setcanceltype(savtype, NULL);
  588.         }
  589.     if (retVal != OK)
  590. {
  591. errno = retVal;
  592. return (ERROR); /* error occurred */
  593. }
  594.     return (OK);
  595.     }
  596. /******************************************************************************* *
  597. *
  598. * aio_cancel - cancel an asynchronous I/O request (POSIX)
  599. *
  600. * This routine attempts to cancel one or more asynchronous I/O request(s) 
  601. * currently outstanding against the file descriptor <fildes>.  <pAiocb> 
  602. * points to the asynchronous I/O control block for a particular request to
  603. * be cancelled.  If <pAiocb> is NULL, all outstanding cancelable 
  604. * asynchronous I/O requests associated with <fildes> are cancelled.
  605. * Normal signal delivery occurs for AIO operations that are successfully 
  606. * cancelled.  If there are requests that cannot be cancelled, then the normal 
  607. * asynchronous completion process takes place for those requests when they 
  608. * complete.
  609. *
  610. * Operations that are cancelled successfully have a return status of -1
  611. * and an error status of ECANCELED.
  612. *
  613. * RETURNS:
  614. *  AIO_CANCELED if requested operations were cancelled,
  615. *  AIO_NOTCANCELED if at least one operation could not be cancelled,
  616. *  AIO_ALLDONE if all operations have already completed, or
  617. *  ERROR if an error occurred.
  618. *
  619. * ERRNO: EBADF
  620. *
  621. * INCLUDE FILES: aio.h
  622. *
  623. * SEE ALSO: aio_return(), aio_error()
  624. */
  625. int aio_cancel
  626.     (
  627.     int fildes, /* file descriptor */
  628.     struct aiocb *  pAiocb /* AIO control block */
  629.     )
  630.     {
  631.     FUNCPTR ioctlRtn; /* ioctl routine */
  632.     AIO_FD_ENTRY * pEntry; /* fd entry */
  633.     DL_NODE * pNode; /* fd node */
  634.     AIO_SYS * pReq; /* AIO request */
  635.     int value; /* driver parameter */ 
  636.     int cancelled = 0; /* num cancelled */
  637.     int retVal = OK; /* return value */
  638.     if ((pEntry = aioEntryFind (fildes)) == NULL)
  639. return (ERROR);
  640.     ioctlRtn = aioDrvTable [pEntry->drv_num].ioctl;
  641.     value = pEntry->drv_value;
  642.     if (pAiocb != NULL) /* cancel a single request */
  643. {
  644. if (pAiocb->aio_state == AIO_COMPLETED)
  645.     return (AIO_ALLDONE);
  646.         if (((* ioctlRtn) (value, FAIO_CANCEL, pAiocb)) == OK)
  647.     return (AIO_CANCELED);
  648. return (AIO_NOTCANCELED);
  649. }
  650.     /* Cancel all requests on the file descriptor */
  651.     semTake (&pEntry->ioQSem, WAIT_FOREVER);
  652.     for (pNode = DLL_FIRST (&pEntry->ioQ); pNode != NULL; 
  653.  pNode = DLL_NEXT (pNode))
  654. {
  655. pReq = FD_NODE_TO_SYS (pNode);
  656. if (pReq->state != AIO_COMPLETED)
  657.     {
  658.     if ((* ioctlRtn) (value, FAIO_CANCEL, pReq->pAiocb) == ERROR)
  659. retVal = AIO_NOTCANCELED;
  660.     else
  661.      cancelled ++;
  662.     }
  663. }
  664.     semGive (&pEntry->ioQSem);
  665.     if (retVal == AIO_NOTCANCELED)
  666. return (AIO_NOTCANCELED); /* couldn't cancel */
  667.     if (cancelled)
  668. return (AIO_CANCELED); /* cancelled */
  669.     return (AIO_ALLDONE);
  670.     }
  671. #if FALSE /* not ready for primetime - kdl 1/26/94 */
  672. /*******************************************************************************
  673. *
  674. * aio_fsync - asynchronous file synchronization (POSIX)
  675. *
  676. * This routine asynchronously forces all I/O operations associated 
  677. * with the file, indicated by `aio_fildes', queued at the time aio_fsync() is 
  678. * called to the synchronized I/O completion state.  aio_fsync() returns 
  679. * when the synchronization request has be initiated or queued to the file or 
  680. * device.
  681. * The value of <op> is ignored.  It currently has no meaning in VxWorks.
  682. *
  683. * If the call fails, the outstanding I/O operations are not guaranteed to
  684. * have completed.  If it succeeds, only the I/O that was queued at the time
  685. * of the call is guaranteed to the relevant completion state.
  686. * The `aio_sigevent' member of the <pAiocb> defines an optional signal to be 
  687. * generated on completion of aio_fsync().
  688. *
  689. * RETURNS: OK if queued successfully, otherwise ERROR.
  690. *
  691. * ERRNO: EINVAL, EBADF
  692. *
  693. * INCLUDE FILES: aio.h
  694. *
  695. * SEE ALSO: aio_error(), aio_return() 
  696. *
  697. * INTERNAL
  698. * Asynchronously synchronize a file??????  Excuse me?  Sounds like an 
  699. * oxymoron (or at least moronic).  At any rate this is hard to implement
  700. * correctly. 
  701. *
  702. * NOMANUAL
  703. */
  704. int aio_fsync
  705.     (
  706.     int op, /* operation */
  707.     struct aiocb *  pAiocb /* AIO control block */
  708.     )
  709.     {
  710.     FUNCPTR ioctlRtn; /* ioctl routine */
  711.     AIO_FD_ENTRY * pEntry; /* fd entry */
  712.     if (pAiocb == NULL)
  713. return (OK); /* not sure what POSIX means */
  714.     if ((pEntry = aioEntryFind (pAiocb->aio_fildes)) == NULL)
  715. return (ERROR);
  716.     /* Submit sync request */
  717.     if (aioSubmit (pAiocb, IO_SYNC, NULL) == ERROR)
  718. return (ERROR);
  719.        
  720.     /* Push request to head of work queue */ 
  721.     ioctlRtn = aioDrvTable [pEntry->drv_num].ioctl;
  722.     (* ioctlRtn) (pEntry->drv_value, FAIO_PUSH, pAiocb);    
  723.     return (OK);
  724.     }
  725. #endif /* FALSE */
  726. /*******************************************************************************
  727. *
  728. * aio_error - retrieve error status of asynchronous I/O operation (POSIX)
  729. *
  730. * This routine returns the error status associated with the I/O operation 
  731. * specified by <pAiocb>.  If the operation is not yet completed, the error 
  732. * status will be EINPROGRESS.
  733. *
  734. * RETURNS:
  735. *  EINPROGRESS if the AIO operation has not yet completed,
  736. *  OK if the AIO operation completed successfully,
  737. *  the error status if the AIO operation failed, 
  738. *  otherwise ERROR.
  739. *
  740. * ERRNO: EINVAL
  741. *
  742. * INCLUDE FILES: aio.h
  743. *
  744. */
  745. int aio_error 
  746.     (
  747.     const struct aiocb * pAiocb /* AIO control block */
  748.     )
  749.     {
  750.     int  state;  /* AIO request state */
  751.     if (pAiocb != NULL)
  752. {
  753. state = pAiocb->aio_state;
  754. if (state == AIO_COMPLETED)
  755.     return (pAiocb->aio_errorVal); /* return error value */
  756.      if ((state >= AIO_READY) && (state <= AIO_RUNNING))
  757.     return (EINPROGRESS); /* still running */
  758. }
  759.     errno = EINVAL;
  760.     return (ERROR); /* unsure about pAiocb */
  761.     }
  762. /*******************************************************************************
  763. *
  764. * aio_return - retrieve return status of asynchronous I/O operation (POSIX)
  765. *
  766. * This routine returns the return status associated with the I/O operation
  767. * specified by <pAiocb>.  The return status for an AIO operation is the 
  768. * value that would be returned by the corresponding read(), write(), or 
  769. * fsync() call.  aio_return() may be called only after the AIO operation
  770. * has completed (aio_error() returns a valid error code--not EINPROGRESS).
  771. * Furthermore, aio_return() may be called only once; subsequent 
  772. * calls will fail.
  773. *
  774. * RETURNS: The return status of the completed AIO request, or ERROR. 
  775. *
  776. * ERRNO:  EINVAL, EINPROGRESS
  777. *
  778. * INCLUDE FILES: aio.h
  779. */
  780. size_t aio_return 
  781.     (
  782.     struct aiocb *  pAiocb /* AIO control block */
  783.     )
  784.     {
  785.     int retVal; /* return value */
  786.     AIO_FD_ENTRY * pEntry; /* fd entry */
  787.     FAST AIO_SYS * pReq;  /* AIO request */
  788.     if (pAiocb == NULL)
  789. {
  790. errno = EINVAL;
  791.   return (ERROR); /* invalid parameter */
  792. }
  793.     if ((pEntry = aioEntryFind (pAiocb->aio_fildes)) == NULL)
  794. return (ERROR);
  795.     pReq = &pAiocb->aio_sys;
  796.     if (pReq->state != AIO_COMPLETED)
  797. {
  798.      errno = EINPROGRESS;
  799. return (ERROR); /* not done yet */
  800. }
  801.     /* Remove the aiocb from the fd list if the aiocb was 
  802.      * submitted correctly. 
  803.      */
  804.     semTake (&pEntry->ioQSem, WAIT_FOREVER);
  805.     if (pReq->pAiocb != NULL)
  806.         dllRemove (&pEntry->ioQ, &pReq->fdNode);
  807.     semGive (&pEntry->ioQSem);
  808.     /* Wait here until all call to suspend (on this aiocb) 
  809.      * wake up and are deleted from wait list. aioDone wakes up 
  810.      * each individual suspend.  
  811.      * aio_suspend() removes them from the wait list.
  812.      */
  813.     mutex_lock (&pReq->lock);
  814.     while (lstCount (&pReq->wait) > 0)
  815. cond_timedwait (&pReq->wake, &pReq->lock, NULL);
  816.     mutex_unlock (&pReq->lock);
  817.     sigPendDestroy (&pReq->sigpend);
  818.     retVal = pAiocb->aio_retVal;
  819.     bzero ((char *) pReq, sizeof (AIO_SYS));
  820.     return (retVal);
  821.     }
  822. /******************************************************************************
  823. *
  824. * aioSubmit - submit an AIO request 
  825. * This routine fills in the AIO_SYS portion, of the AIO control block (pAiocb)
  826. * then passes the request to the AIO driver by calling the driver supplied 
  827. * insert routine.
  828. *
  829. * RETURNS: OK if successful, ERROR otherwise
  830. *
  831. * ERRNO: EINVAL
  832. * INTERNAL
  833. * The state leaving this routine is AIO_READY.  The driver provided insert 
  834. * routine must mark the state as AIO_QUEUED after inserting it onto the 
  835. * workQ.
  836. */
  837. LOCAL STATUS aioSubmit
  838.     (
  839.     struct aiocb * pAiocb, /* AIO control block */
  840.     int op, /* operation */
  841.     AIO_CLUST * pClust /* cluster */
  842.     )
  843.     {
  844.     FUNCPTR insertRtn; /* insert routine */
  845.     AIO_FD_ENTRY * pEntry; /* fd entry */
  846.     AIO_SYS * pReq; /* AIO request */
  847.     int prio = 0; /* priority */
  848.     if (pAiocb == NULL)
  849. {
  850. errno = EINVAL;
  851.   return (ERROR); /* safety check */
  852. }
  853.     if ((pAiocb->aio_sigevent.sigev_notify == SIGEV_SIGNAL) &&
  854. ((pAiocb->aio_sigevent.sigev_signo < 1) ||
  855.  (pAiocb->aio_sigevent.sigev_signo > _NSIGS)))
  856. {
  857. errno = EINVAL;
  858.   return (ERROR); /* safety check */
  859. }
  860.     pReq = &pAiocb->aio_sys; /* clear AIO_SYS */
  861.     bzero ((char *) pReq, sizeof (AIO_SYS));
  862.     if ((pEntry = aioEntryFind (pAiocb->aio_fildes)) == NULL)
  863. return (ERROR);
  864.     /* #ifdef _POSIX_PRIORITIZED_IO (says POSIX) but implementing 
  865.      * this here is easy.  Let the driver decide what to do with it.
  866.      */
  867.     if ((pAiocb->aio_reqprio < 0) || 
  868. (pAiocb->aio_reqprio > AIO_PRIO_DELTA_MAX))
  869. {
  870. errno = EINVAL;
  871. return (ERROR); /* invalid priority */
  872. }
  873.     
  874.     /* Determine the effective priority - use VxWorks numbering */
  875.     taskPriorityGet (taskIdSelf (), &prio);
  876.     prio = min ((pAiocb->aio_reqprio + prio), VXWORKS_LOW_PRI);
  877.     /* initialize the AIO control block */
  878.     pReq->ioNode.op  = op; /* fill in the ioNode */
  879.     pReq->ioNode.prio  = prio;
  880.     pReq->ioNode.doneRtn = aioDone;
  881.     pReq->ioNode.taskId  = taskIdSelf ();
  882.     pReq->ioNode.errorVal= EINPROGRESS;
  883.     pReq->ioNode.retVal  = OK;
  884.     pReq->pAiocb         = pAiocb; /* back pointer */
  885.     pReq->pClust  = pClust; /* cluster */
  886.     lstInit (&pReq->wait); /* initailize wait */
  887.     mutex_init (&pReq->lock, NULL);
  888.     cond_init (&pReq->wake, NULL);
  889.     pReq->state   = AIO_READY; /* mark it ready */
  890.     semTake (&pEntry->ioQSem, WAIT_FOREVER);
  891.     if (!pEntry->ioQActive)
  892. {
  893.      semGive (&pEntry->ioQSem);
  894. errno = EBADF;
  895. return (ERROR); /* was deleted */
  896. }
  897.     dllAdd (&pEntry->ioQ, &pReq->fdNode); /* add it to fd list */
  898.     semGive (&pEntry->ioQSem);
  899.     insertRtn = aioDrvTable [pEntry->drv_num].insert;
  900.     return ((* insertRtn) (pEntry->drv_value, pAiocb, prio));
  901.     }
  902. /*****************************************************************************
  903. *
  904. * aioListEach - call routine for each element in list
  905. *
  906. * This routine calls the passed routine <routine> with arguments <arg1>
  907. * and <arg2> for each element in <list> which is non null.  <list>
  908. * has <num> elements.  aioListEach calls the passed function <routine> 
  909. * until <routine> returns a value of FALSE.  
  910. *
  911. * RETURNS:  the index of in <list> which caused aioList() to stop (return FALSE)
  912. *      or <num> if all members of the list element returned TRUE.
  913. */
  914. LOCAL int aioListEach
  915.     (
  916.     struct aiocb *  list[], /* list of operations */
  917.     int num, /* size of list */
  918.     FUNCPTR routine, /* routine to call */
  919.     int arg1, /* argument */
  920.     int arg2 /* argument */
  921.     )
  922.     {
  923.     int  ix; /* index */
  924.     for (ix = 0; ix < num; ix++)
  925. {
  926. if (list [ix] != NULL) 
  927.     {
  928.     if (((* routine) (list [ix], arg1, arg2)) == FALSE)
  929. return (ix);
  930.     }
  931.     return (num);
  932.     } 
  933. /*****************************************************************************
  934. *
  935. * aioListSubmit - submit a list of AIO requests (aioListEach routine)
  936. *
  937. * This routine is called from lio_listio() to submit the list of AIO
  938. * requests.  aioListSubmit submits each element of the list, even of
  939. * on fails.
  940. * RETURNS: TRUE
  941. */
  942. LOCAL BOOL aioListSubmit
  943.     (
  944.     struct aiocb * pAiocb,  /* AIO control block */
  945.     AIO_CLUST *  pClust, /* cluster */
  946.     BOOL * pFailed  /* set if submit failed */
  947.     )
  948.     {
  949.     int op = pAiocb->aio_lio_opcode;
  950.     switch (op)
  951. {
  952. case LIO_READ  : op = IO_READ; break;
  953. case LIO_WRITE : op = IO_WRITE; break;
  954. case LIO_NOP   : return (TRUE);  /* NOP is dumb, but valid */
  955. }
  956.     if (aioSubmit (pAiocb, op, pClust) == ERROR)
  957. {
  958. AIO_DONE_SET (pAiocb, ERROR, errno);
  959. *pFailed = TRUE; /* notify caller failure */ 
  960. aioClustRet (pAiocb, pClust);
  961. }
  962.     return (TRUE);
  963.     }
  964. /*****************************************************************************
  965. *
  966. * aioListClust - cluster AIO requests together (aioListEach routine)
  967. *
  968. * This routine is called from lio_listio() to cluster the list of AIO
  969. * requests together.
  970. * RETURNS: TRUE
  971. */
  972. LOCAL BOOL aioListClust
  973.     (
  974.     struct aiocb * pAiocb,  /* AIO control block */
  975.     AIO_CLUST * pClust, /* cluster */
  976.     int bogus1 /* not used */
  977.     )
  978.     {
  979.     if (pAiocb->aio_lio_opcode != LIO_NOP)
  980. pClust->refCnt++; /* count number of aiocbs */
  981.     return (TRUE);
  982.     }
  983. /*****************************************************************************
  984. *
  985. * aioListError - check for errors in list (aioListEach routine)
  986. *
  987. * This routine is called from lio_listio() to check if any of the completed
  988. * AIO requests in the list failed.
  989. *
  990. * RETURNS: FALSE if any request failed, TRUE otherwise.
  991. */
  992. LOCAL BOOL aioListError 
  993.     (
  994.     struct aiocb * pAiocb, /* AIO control block */
  995.     int * pError, /* error */
  996.     int bogus /* not used */
  997.     )
  998.     {
  999.     if ((pAiocb->aio_lio_opcode != LIO_NOP) && 
  1000. (pAiocb->aio_state == AIO_COMPLETED) && 
  1001. (pAiocb->aio_retVal == ERROR))
  1002. {
  1003. *pError = pAiocb->aio_errorVal;
  1004. return (FALSE);
  1005. }
  1006.     return (TRUE);
  1007.     }
  1008.     
  1009. /*****************************************************************************
  1010. *
  1011. * aioListWait - add wait request to AIO control block (aioListEach routine).
  1012. *
  1013. * This routine is called from aio_suspend() to add the <pAioId> to the wait 
  1014. * list associated with <pAiocb>.
  1015. *
  1016. * RETURNS: FALSE if an error occurred or any request had completed
  1017. *    TRUE otherwise
  1018. */
  1019. LOCAL BOOL aioListWait
  1020.     (
  1021.     struct aiocb * pAiocb,  /* AIO control block */
  1022.     AIO_WAIT_ID * pAioId, /* AIO id */
  1023.     int bogus /* not used */
  1024.     )
  1025.     {
  1026.     FAST AIO_FD_ENTRY * pEntry; /* fd entry */
  1027.     STATUS retVal = TRUE; /* return value */
  1028.     AIO_SYS * pReq   = &pAiocb->aio_sys;
  1029.     if ((pEntry = aioEntryFind (pAiocb->aio_fildes)) == NULL)
  1030. return (FALSE); /* invalid file */
  1031.     mutex_lock (&pReq->lock);
  1032.     if ((pReq->state >= AIO_READY) && (pReq->state <= AIO_RUNNING))
  1033. lstAdd (&pReq->wait, &pAioId->node);
  1034.     else
  1035. {
  1036. errno = (pReq->state == AIO_COMPLETED) ? AIO_COMPLETED : EINVAL;
  1037. retVal = FALSE;
  1038. }
  1039.     mutex_unlock (&pReq->lock);
  1040.     return (retVal);
  1041.     }
  1042. /*****************************************************************************
  1043. *
  1044. * aioListUnwait - delete previous wait request (aioListEach routine).
  1045. *
  1046. * This routine cancels a previous wait request.  It deletes the <pAioId>
  1047. * from the wait list associated with <pAiocb>.
  1048. *
  1049. * RETURNS: TRUE
  1050. */
  1051. LOCAL BOOL aioListUnwait
  1052.     (
  1053.     struct aiocb * pAiocb,  /* AIO control block */
  1054.     AIO_WAIT_ID * pAioId, /* AIO id */
  1055.     int bogus /* not used */
  1056.     )
  1057.     {
  1058.     mutex_lock (&pAiocb->aio_sys.lock);
  1059.     lstDelete (&pAiocb->aio_sys.wait, &pAioId->node);
  1060.     mutex_unlock (&pAiocb->aio_sys.lock);
  1061.     return (TRUE);
  1062.     }
  1063. /*******************************************************************************
  1064. * aioClustGet - get a free cluster 
  1065. *
  1066. * RETURNS: A pointer to a cluster structure or NULL.
  1067. */
  1068. LOCAL AIO_CLUST * aioClustGet (void)
  1069.     {
  1070.     int  ix; /* index */
  1071.     AIO_CLUST * pClust; /* AIO cluster */
  1072.     AIO_LOCK (); /* lock access */
  1073.     for (ix = 0; ix < aioClustMax; ix++)
  1074. {
  1075.         if (!aioClustTable [ix].inuse)
  1076.     {
  1077.     aioClustTable [ix].inuse = TRUE;
  1078.     break; /* got free cluster */
  1079.     }
  1080. }
  1081.     AIO_UNLOCK (); /* unlock access */
  1082.     if (ix >= aioClustMax)
  1083. {
  1084.         errno = EAGAIN;
  1085. return (NULL); /* none available */
  1086. }
  1087.     /* Initialize cluster */
  1088.     pClust = &aioClustTable [ix];
  1089.     pClust->refCnt = 0;
  1090.     mutex_init (&pClust->lock, NULL);
  1091.     cond_init  (&pClust->wake, NULL);
  1092.     return (pClust);
  1093.     }
  1094. /*******************************************************************************
  1095. * aioDone - AIO completed 
  1096. *
  1097. * This routine gets called on completion of an AIO operation.  It notifies
  1098. * any waiting tasks of the AIO completion.  When aioDone is called the 
  1099. * AIO request should not be associated with any driver workQ and the 
  1100. * state should have been set to AIO_COMPLETED and the return and error 
  1101. * values set.  aioDone shouldnt't be called from interrupt service 
  1102. * routine (if so, it gets deffered to excTask).
  1103. *
  1104. * RETURNS: N/A
  1105. *
  1106. * NOMANUAL
  1107. */
  1108. void aioDone 
  1109.     (
  1110.     AIO_SYS *  pReq /* AIO request */
  1111.     )
  1112.     {
  1113.     AIO_WAIT_ID * pWaitId; /* wait request id */
  1114.     struct aiocb * pAiocb = pReq->pAiocb; /* AIO control block */
  1115.     if (INT_CONTEXT ())
  1116. {
  1117. excJobAdd ((VOIDFUNCPTR) aioDone, (int) pReq, 0, 0, 0, 0, 0);
  1118. return;
  1119. }
  1120.     if (aioPrintRtn != NULL)
  1121. (* aioPrintRtn) ("aioDone: aiocb (0x%x) retVal %d error 0x%xn", 
  1122.  (int) pAiocb, pAiocb->aio_retVal, 
  1123.  pAiocb->aio_errorVal, 0, 0, 0);
  1124.     /* Wake tasks waiting in aio_suspend */
  1125.     mutex_lock (&pReq->lock);
  1126.     
  1127.     for (pWaitId = (AIO_WAIT_ID *) lstFirst (&pReq->wait); (pWaitId != NULL); 
  1128.  pWaitId = (AIO_WAIT_ID *) lstNext (&pWaitId->node))
  1129. {
  1130. mutex_lock (&pWaitId->lock);
  1131.    
  1132. if (!pWaitId->done)
  1133.     pWaitId->done = TRUE;
  1134. cond_signal (&pWaitId->wake);
  1135. mutex_unlock (&pWaitId->lock);
  1136. }
  1137.     mutex_unlock (&pReq->lock);
  1138.     /* We lock out the task because even though we signaled it
  1139.      * we don't want it to run until we marked it completed.
  1140.      */
  1141.      
  1142.     taskLock ();
  1143.     if (pReq->pClust != NULL)
  1144. aioClustRet (pAiocb, pReq->pClust);
  1145.     /* Send a caller specified signal */
  1146.     if (pAiocb->aio_sigevent.sigev_notify == SIGEV_SIGNAL)
  1147. {
  1148. if (aioPrintRtn != NULL)
  1149.     (* aioPrintRtn) ("aioDone: signal %dn",
  1150.      pAiocb->aio_sigevent.sigev_signo, 0, 0, 0, 0, 0);
  1151. sigPendInit (&pReq->sigpend);
  1152. pReq->sigpend.sigp_info.si_signo = pAiocb->aio_sigevent.sigev_signo;
  1153. pReq->sigpend.sigp_info.si_code  = SI_ASYNCIO;
  1154. pReq->sigpend.sigp_info.si_value = pAiocb->aio_sigevent.sigev_value;
  1155. sigPendKill (pReq->ioNode.taskId, &pReq->sigpend);
  1156. }
  1157.     pReq->state = AIO_COMPLETED;
  1158.     taskUnlock ();
  1159.     }
  1160. /*******************************************************************************
  1161. * aioClustRet - return a cluster
  1162. *
  1163. * This routine frees <pClust> and  signals/wakes up the initiating task if
  1164. * <pAiocb> is the last AIO request in the cluster.
  1165. *
  1166. * RETURN: N/A
  1167. *
  1168. * NOMANUAL
  1169. */
  1170. LOCAL void aioClustRet
  1171.     (
  1172.     struct aiocb  * pAiocb, /* AIO control block */
  1173.     AIO_CLUST * pClust /* AIO cluster */
  1174.     )
  1175.     {
  1176.     BOOL returnClust; /* cluster goes to table */ 
  1177.     int signo; /* signal number */
  1178.     int taskId; /* lio_listio() task */
  1179.     if (pClust == NULL)
  1180. return; 
  1181.     mutex_lock (&pClust->lock);
  1182.     returnClust = ((pClust->refCnt > 0) && (--pClust->refCnt == 0));
  1183.     mutex_unlock (&pClust->lock);
  1184.     /* If we are the last one in the cluster.  Signal/wake up the caller
  1185.      * and return the cluster.
  1186.      */
  1187.     if (returnClust)
  1188. {
  1189. signo = pClust->sigpend.sigp_info.si_signo;
  1190. taskId  = pAiocb->aio_sys.ioNode.taskId;
  1191. if (aioPrintRtn != NULL)
  1192.     (* aioPrintRtn) ("clust done signal (%d) to task %xn", signo, 
  1193.      taskId, 0, 0, 0, 0);
  1194. /* send the user defined signal */
  1195. if (signo != 0)
  1196.     {
  1197.     sigPendKill (taskId, &pClust->sigpend);
  1198.     }
  1199. else
  1200.     {
  1201.     /* wake up waiting process */
  1202.     cond_signal (&pClust->wake);
  1203.     }
  1204. pClust->inuse = FALSE; /* free cluster */
  1205. }
  1206.     }
  1207.  
  1208. /* DRIVER INTERFACE ROUTINES */
  1209. /*******************************************************************************
  1210. * aioDrvInstall - install an AIO driver 
  1211. *
  1212. * This routine is called by an I/O driver to specify it supports AIO and 
  1213. * to insert it's AIO routines into the AIO driver table.  <drvnum> is 
  1214. * the driver number to install.   <pInsert> is the AIO insert routine.
  1215. * <pIoctl> the the AIO ioctl routine.  <flags> gets filled into the 
  1216. * driver specific flags member of the AIO_DRV_ENTRY structure.  
  1217. *
  1218. * RETURNS: OK if successful, otherwise ERROR.
  1219. *
  1220. * ERRNO: S_aioPxLib_DRV_NUM_INVALID
  1221. *
  1222. * INTERNAL:  The aioDrvTable is similar to the drvTable in iosLib.  
  1223. * aioDrvTable (and this routine) might go away if aioLib is more 
  1224. * integrated into iosLib.   Don't man this page until driver interface
  1225. * is documented and supported.
  1226. *
  1227. * NOMANUAL
  1228. */
  1229. STATUS aioDrvInstall 
  1230.     (
  1231.     int drvnum, /* driver number */
  1232.     FUNCPTR pInsert, /* insert routine */
  1233.     FUNCPTR pIoctl, /* ioctl routine */
  1234.     int flags /* driver flags */
  1235.     )
  1236.     {
  1237.     AIO_LOCK ();
  1238.     if ((drvnum < 0) || (drvnum >= maxDrivers) || aioDrvTable [drvnum].inuse)
  1239. {
  1240. errno = S_aioPxLib_DRV_NUM_INVALID;
  1241. return (ERROR); /* invalid driver number */
  1242. }
  1243.     aioDrvTable [drvnum].insert = pInsert; /* add to driver table */
  1244.     aioDrvTable [drvnum].ioctl  = pIoctl;
  1245.     aioDrvTable [drvnum].flags  = flags;
  1246.     AIO_UNLOCK ();
  1247.     return (OK);
  1248.     }
  1249. /*******************************************************************************
  1250. * aioDrvFlagsGet - get AIO driver flags
  1251. *
  1252. * RETURNS: OK if successful, otherwise ERROR.
  1253. *
  1254. * NOMANUAL
  1255. */
  1256. STATUS aioDrvFlagsGet 
  1257.     (
  1258.     int fd,  /* file descriptor */
  1259.     int * pFlags /* return flags */
  1260.     )
  1261.     {
  1262.     AIO_FD_ENTRY *  pEntry;  /* fd entry */
  1263.     if ((pEntry = aioEntryFind (fd)) == NULL)
  1264. return (ERROR);  /* error condition */
  1265.     *pFlags = aioDrvTable [pEntry->drv_num].flags;
  1266.     return (OK);
  1267.     }
  1268. /*******************************************************************************
  1269. * aioDrvFlagsSet - set AIO driver flags
  1270. *
  1271. * RETURNS: OK if successful, otherwise ERROR.
  1272. *
  1273. * NOMANUAL
  1274. */
  1275. STATUS aioDrvFlagsSet
  1276.     (
  1277.     int fd,  /* file descriptor */
  1278.     int flags /* flags to set */
  1279.     )
  1280.     {
  1281.     AIO_FD_ENTRY *  pEntry;  /* fd entry */
  1282.     if ((pEntry = aioEntryFind (fd)) == NULL)
  1283. return (ERROR);  /* error condition */
  1284.     aioDrvTable [pEntry->drv_num].flags |= flags;
  1285.     return (OK); 
  1286.     }
  1287. /*******************************************************************************
  1288. * aioNext - obtain next AIO request to initiate
  1289. *
  1290. * This routine obtains the next available AIO request in the work queue. 
  1291. * It finds the first request where the state is AIO_QUEUED. 
  1292. *
  1293. * RETURNS: pointer to next queued AIO control block or NULL
  1294. *
  1295. * NOMANUAL
  1296. */
  1297. AIO_SYS * aioNext
  1298.     (
  1299.     AIO_DEV * pDev /* AIO device */
  1300.     )
  1301.     {
  1302.     AIO_SYS * pReq = NULL; /* AIO request */
  1303.     LIST * pWorkQ = &pDev->ioQ.workQ; /* work queue */
  1304.     IOQ_LOCK (&pDev->ioQ);
  1305.     for (pReq = (AIO_SYS *) lstFirst (pWorkQ); (pReq != NULL); 
  1306.  pReq = (AIO_SYS *) lstNext (&pReq->ioNode.node))
  1307. {
  1308. if (pReq->state == AIO_QUEUED) 
  1309.     {
  1310.     pReq->state = AIO_RUNNING;
  1311.     break;
  1312.     }
  1313. }
  1314.     IOQ_UNLOCK (&pDev->ioQ);
  1315.     return (pReq);
  1316.     }
  1317. /*****************************************************************************
  1318. *
  1319. * aioCancel - cancel an AIO request 
  1320. *
  1321. * This routine tries to cancel an AIO request.  If the state of the AIO
  1322. * request is not running, the request is deleted from the work queue 
  1323. * <pDev->workQ> and completed with a return value of -1 and an error 
  1324. * value of ECANCELED.
  1325. *
  1326. * RETURNS: ERROR if request is RUNNING, otherwise OK.
  1327. *
  1328. * NOMANUAL
  1329. */
  1330. STATUS aioCancel
  1331.     (
  1332.     AIO_DEV * pDev, /* AIO device */
  1333.     struct aiocb * pAiocb /* AIO control block */
  1334.     )
  1335.     {
  1336.     int state; /* state */
  1337.     IO_Q * pQ = &pDev->ioQ; /* queue */
  1338.     AIO_SYS * pReq = &pAiocb->aio_sys;/* AIO request */
  1339.     IOQ_LOCK (pQ); /* lock the ioQ */
  1340.     state = pReq->state;
  1341.     if (state == AIO_RUNNING)
  1342. {
  1343. IOQ_UNLOCK (pQ);
  1344.         return (ERROR); /* can't cancel running */
  1345. }
  1346.     if (state == AIO_QUEUED) 
  1347. IOQ_WORK_DELETE (pQ, &pReq->ioNode);
  1348.     else
  1349. {
  1350. if (state == AIO_WAIT)
  1351.     IOQ_WAIT_DELETE (pQ, &pReq->ioNode);
  1352. }
  1353.     AIO_DONE_SET (pAiocb, ERROR, ECANCELED); /* mark it as cancelled */
  1354.     IOQ_UNLOCK (pQ); /* unlock ioQ */
  1355.     ioQNodeDone (&pReq->ioNode);
  1356.     return (OK);
  1357.     }
  1358. /*****************************************************************************
  1359. *
  1360. * aioPush - push a queued request to head of work queue.
  1361. *
  1362. * RETURNS: OK if successful, otherwise ERROR.
  1363. *
  1364. * NOMANUAL
  1365. */
  1366. STATUS aioPush 
  1367.     (
  1368.     AIO_DEV * pDev, /* AIO device */
  1369.     struct aiocb * pAiocb /* AIO request */
  1370.     )
  1371.     {
  1372.     IO_Q * pQ    = &pDev->ioQ;
  1373.     IO_NODE * pNode = &pAiocb->aio_sys.ioNode;
  1374.     IOQ_LOCK (pQ);
  1375.     if (pAiocb->aio_state == AIO_QUEUED)
  1376. {
  1377. IOQ_WORK_DELETE (pQ, pNode);
  1378. IOQ_WORK_ADD_HEAD (pQ, pNode);
  1379. }
  1380.     
  1381.     IOQ_UNLOCK (pQ);
  1382.     return (OK);
  1383.     }
  1384. /*****************************************************************************
  1385. *
  1386. * aioSync - synchronize
  1387. *
  1388. * This routine synchronizes all AIO requests assoicated with file descriptor
  1389. * <pAiocb->aio_fildes>.  <syncReqRtn> specifies a driver provided 
  1390. * synchronization routine that gets called for each request associated with 
  1391. * the above specified file.  After each AIO request has been synchronized,
  1392. * it is returned to the library via aioDone.
  1393. *
  1394. * RETURNS: OK, or ERROR if couldn't find entry.
  1395. *
  1396. * NOMANUAL
  1397. */
  1398. STATUS aioSync 
  1399.     (
  1400.     AIO_DEV * pDev, /* AIO device */
  1401.     struct aiocb *  pAiocb, /* aio control block */
  1402.     FUNCPTR syncReqRtn /* routine to sync a request */
  1403.     )
  1404.     {
  1405.     FAST AIO_FD_ENTRY * pEntry; /* fd entry */
  1406.     ARGS  args;
  1407.     int fd = pAiocb->aio_fildes;
  1408.     if ((pEntry = aioEntryFind (fd)) == NULL)
  1409. return (ERROR);
  1410.     args.pDev     = pDev; /* device */
  1411.     args.retVal   = OK; /* return */
  1412.     args.errorVal = 0; /* errno */
  1413.     args.syncRtn  = syncReqRtn;
  1414.     semTake (&pEntry->ioQSem, WAIT_FOREVER);
  1415.     dllEach (&pEntry->ioQ, aioSyncNode, (int) &args);
  1416.     semGive (&pEntry->ioQSem);
  1417.     if (ioctl (fd, FIOSYNC, 0) == ERROR)
  1418.      ioctl (fd, FIOFLUSH, 0);
  1419.     /* one for the  aio_fsync() request */
  1420.     IOQ_LOCK (&pDev->ioQ);
  1421.     AIO_DONE_SET (pAiocb, args.retVal, args.errorVal);
  1422.     IOQ_WORK_DELETE (&pDev->ioQ, &pAiocb->aio_sys.ioNode);
  1423.     IOQ_UNLOCK (&pDev->ioQ);
  1424.     ioQNodeDone (&pAiocb->aio_sys.ioNode);
  1425.     return (OK);
  1426.     }
  1427. /*****************************************************************************
  1428. *
  1429. * aioSyncNode - synchronize an AIO request
  1430. * This routine gets called from aioSync for each AIO request on the fd list.
  1431. * It calls the driver provided sync routine for each request whose 
  1432. * state is not completed. 
  1433. */
  1434. LOCAL STATUS aioSyncNode
  1435.     (
  1436.     DL_NODE * pFdNode, /* node on fd list */
  1437.     ARGS * pArgs /* arguments */
  1438.     )
  1439.     {
  1440.     AIO_SYS * pReq; /* AIO request */
  1441.     BOOL retVal = TRUE; /* return value */
  1442.     pReq = FD_NODE_TO_SYS (pFdNode); 
  1443.     if (pReq->state != AIO_COMPLETED)
  1444. {
  1445.      if (((* pArgs->syncRtn) (pArgs->pDev, pReq)) == ERROR)
  1446.     {
  1447.     pArgs->retVal = ERROR;
  1448.     pArgs->errorVal = errno;
  1449.        retVal = FALSE;
  1450.        }
  1451. }
  1452.     return (retVal);
  1453.     }
  1454. /* The following routines are support routines for iosLib.  They wont 
  1455.  * be needed if fully integerated into the I/O system.
  1456.  */
  1457. /*****************************************************************************
  1458. *
  1459. * aioFdNew - initialize an AIO file descriptor
  1460. *
  1461. * This routine gets called from iosFdNew when allocating a new file
  1462. * descriptor. 
  1463. *
  1464. * RETURNS: N/A
  1465. */
  1466. LOCAL void aioFdNew
  1467.     (
  1468.     int fd /* file descriptor */
  1469.     )
  1470.     {
  1471.     AIO_FD_ENTRY * pEntry   = &aioFdTable [STD_UNFIX(fd)];
  1472.     semTake (&pEntry->ioQSem, WAIT_FOREVER);
  1473.     dllInit (&pEntry->ioQ);
  1474.     pEntry->ioQActive = TRUE;
  1475.     semGive (&pEntry->ioQSem);
  1476.     }
  1477. /*****************************************************************************
  1478. *
  1479. * aioFdFree - free a file descriptor
  1480. *
  1481. * This routine gets called from iosFdFree after closing a file descriptor. 
  1482. * It cancels (or waits for, if it can't cancel) all the outstanding AIO
  1483. * submitted to file descriptor <fd>.
  1484. *
  1485. * RETURNS: N/A
  1486. */
  1487. LOCAL void aioFdFree
  1488.     (
  1489.     int fd /* file descriptor */
  1490.     )
  1491.     {
  1492.     AIO_SYS * pReq; /* AIO request */
  1493.     DL_NODE * pNode; /* fd node */
  1494.     FAST AIO_FD_ENTRY * pEntry = &aioFdTable [STD_UNFIX(fd)];
  1495.     semTake (&pEntry->ioQSem, WAIT_FOREVER);
  1496.     FOREVER 
  1497. {
  1498. if ((pNode = DLL_FIRST (&pEntry->ioQ)) == NULL)
  1499.     break; /* list empty */
  1500.         
  1501. pReq = FD_NODE_TO_SYS (pNode);
  1502. /* Try to cancel it.  If can't, then wait for it */
  1503. if (aio_cancel (fd, pReq->pAiocb) == AIO_NOTCANCELED)
  1504.     aio_suspend ((const struct aiocb **) &pReq->pAiocb, 1, 
  1505.  (const struct timespec *) NULL);
  1506. dllRemove (&pEntry->ioQ, pNode); /* remove it */
  1507. }
  1508.     
  1509.     pEntry->ioQActive = FALSE;
  1510.     semGive (&pEntry->ioQSem);
  1511.     }
  1512. /*****************************************************************************
  1513. *
  1514. * aioEntryFind - find the aio fd entry
  1515. *
  1516. * aiEntryFind validates <fd> and finds the AIO_FD_ENTRY associated with
  1517. * <fd>. 
  1518. *
  1519. * RETURNS: a pointer to the AIO_FD_ENTRY or NULL if error.
  1520. *
  1521. * NOMANUAL
  1522. */
  1523. AIO_FD_ENTRY * aioEntryFind 
  1524.     (
  1525.     int  fd /* file descriptor */
  1526.     )
  1527.     {
  1528.     int xfd = STD_MAP (fd); /* mapped fd */
  1529.     if (FD_CHECK (xfd) == NULL)
  1530. {
  1531. errno = EBADF;
  1532. return (NULL); /* file descriptor invalid */
  1533. }
  1534.     return (&aioFdTable [xfd]);
  1535.     }