📄 wvlib.c
字号:
* Setting exitWhenEmpty to false is used to continuously upload events as* they are logged to the buffer. The semaphore uploadCompleteSem, also* contained in the WV_UPLOADTASK_ID, is given when the this routine has* emptied the buffer. This allows others to wait until the buffer is* empty.** If an error occurs when reading from the buffers or writing to the upload* path, event logging is stopped and the upload path is closed. The status* field in the WV_UPLOADTASK_ID indicates whether the upload was successful* or if an error occurred. When writing to the upload path, if an EAGAIN* or EWOULDBLOCK error is encountered due to a failure to write to a non-* blocking path, this routine will backoff and retry to write to the path.* The number of times to attempt writing, and the the amount of time to* delay between attempts can be set with the global variables** int wvUploadMaxAttempts -- 200 by default* int wvUploadRetryBackoff -- 6 by default (in ticks)** If the block of data, usually one threshold in size, can not be written* within the maximum number of attempts, this routine will stop event * logging, close the upload path and indicate the error within the status* field of the WV_UPLOADTASK_ID.** To avoid copying the event data to a local buffer, only to be copied again* to the upload path, reading the buffer is done using a reserve/commit* interface. Reserving a number of bytes to read from the buffer provides* access, via a pointer, directly to the event data in the buffer. This* pointer references only contiguous memory and can be passed directly to the* upload mechanism. Hence no extra copying is employed. The buffer's* commit interface is used to notify the buffering mechanism that the* reserved memory has been consumed.** The semaphore on which wvUpload blocks works together with the threshold,* also part of the BUFFER_ID, as a general purpose mechanism for telling* users of the buffer when threshold bytes of data are contained in the* buffer. This gives the the uploader a way of controlling the frequency * and size of uploads. The threshold is assigned by the buffer mechanism,* but can be an arbitrary value. In general, the buffer may assign threshold* to meet a buffer contraint, or it may allow the user to assign it, and * allow access to its value in the structure pointed to by the BUFFER_ID.** All buffer accesses are protected with interrupts locked out.** RETURNS: OK when buffer is successfully emptied and uploaded and* the upload task ID's exitWhenEmpty is set to TRUE.* ERROR if an error occurs with the upload path or buffers; event* logging is stopped if an error occurs.** SEE ALSO:* NOMANUAL**/static STATUS wvUpload ( WV_UPLOADTASK_ID upTaskId /* this task's descriptor */ ) { int nReserved; /* num bytes reserved and possible to upload */ int nToWrite; /* num bytes that should be written to host */ int nUploaded; /* number of bytes actually written to host */ int nToCommit; /* number of bytes to commit in the buffer */ int tmp; /* temporary used to count uploaded bytes */ BOOL bufferEmpty; /* used to exit when buffer is empty */ UINT8 *pData; /* pointer to the read-reserved data */ int lockKey; /* for interrupt locking */ BUFFER_ID bufId; /* convenient access to upTaskId->bufferId */ UPLOAD_ID pathId; /* same for upTaskId->uploadPathId */ /* Check that the upload-task id has appropriate information. */ if (upTaskId == NULL) return (ERROR); if (upTaskId->bufferId == NULL) { upTaskId->status = ERROR; return (ERROR); } if (upTaskId->uploadPathId == NULL) { upTaskId->status = ERROR; return (ERROR); } /* Initialize variables. */ bufId = upTaskId->bufferId; pathId = upTaskId->uploadPathId; bufferEmpty = FALSE; nToWrite = 0; while (TRUE) { /* * Initialize variables that allow us to stop uploading at the right * time. Assuming that there is data in the buffer (bufferEmtpy = * FALSE) is alright because nothing below will error if there is * not. In other words, bufferEmpty accurately describes when the * buffer is empty but does not accurately describe when the buffer * is not empty. */ nUploaded = 0; bufferEmpty = FALSE; /* * If the caller requested to exit when the buffer is empty, give * him/er the result immediately, even if there is no data available. * Also, if there is still more than a threshold of data in the buffer, * continue uploading. Otherwise block until sufficient data becomes * available. */ lockKey = intLock (); tmp = bufId->nBytesRtn (bufId); intUnlock (lockKey); if (! upTaskId->exitWhenEmpty && (tmp < bufId->threshold)) semTake (& bufId->threshXSem, WAIT_FOREVER); /* * Upload in chunks of size bufId->threshold. The readReserve * routine of the buffer only guarantees that every time the * threshXSem is able to be taken there are threshold bytes of data * in the buffer. That data may not be contiguous, and so we have * to loop until threshold bytes have been uploaded. */ while ((nUploaded < bufId->threshold) && !bufferEmpty) { /* Reserve as many contiguous bytes as possible from the buffer. */ lockKey = intLock (); nReserved = bufId->readReserveRtn (bufId, &pData); intUnlock (lockKey); if (nReserved == ERROR) { /* * If an error occurs close the upload path and stop event * logging. There is no harm in turning event logging off * if it is not currently on. */ lockKey = intLock (); wvEvtLogStop(); intUnlock (lockKey); pathId->errorRtn (pathId); upTaskId->status = ERROR; logMsg ("tWvUpload: failed to read from buffer.\n", 0, 0, 0, 0, 0, 0); return (ERROR); } /* Notice when the buffer is emptied. */ if (nReserved == 0) bufferEmpty = TRUE; else bufferEmpty = FALSE; /* * Write as many bytes as possible that still need to be uploaed, * to the host, but not more than threshold. And, remember how * many to commit later. */ nToWrite = (nReserved > (bufId->threshold - nUploaded)) ? (bufId->threshold - nUploaded) : nReserved; nToCommit = nToWrite; if (uploadPathWrite (pathId, pData, nToWrite) == ERROR) { /* * There is still no harm in turning off event logging * if it is not currently on. */ lockKey = intLock (); wvEvtLogStop(); intUnlock (lockKey); pathId->errorRtn (pathId); upTaskId->status = ERROR; logMsg ("tWVUpload: failed writing to host.\n", 0, 0, 0, 0, 0, 0); return (ERROR); } /* * At this point all the reserved bytes that were possible to * read in this pass through the loop have been uploaded. Those * bytes are committed before determining whether to loop again. */ lockKey = intLock (); tmp = bufId->readCommitRtn (bufId, nToCommit); intUnlock (lockKey); if (tmp == ERROR) { /* * There is no harm in turning logging off if it is already * off. */ lockKey = intLock (); wvEvtLogStop(); intUnlock (lockKey); pathId->errorRtn (pathId); upTaskId->status = ERROR; logMsg ("tWvUpload: failed to commit uploaded bytes.\n", 0, 0, 0, 0, 0, 0); return (ERROR); } nUploaded += nToCommit; } /* * At this point the buffer is empty or threshold bytes have been * uploaded. Exit only if the buffer was emptied and the user * requested not to wait for more data. */ if (upTaskId->exitWhenEmpty && bufferEmpty) { upTaskId->status = OK; semGive (& upTaskId->uploadCompleteSem); return (OK); } } }/********************************************************************************* wvUploadStart - start upload of events to the host (WindView)** This routine starts uploading events from the event buffer to the host.* Events can be uploaded either continuously or in one pass until the* buffer is emptied. If <uploadContinuously> is set to TRUE, the task* uploading events pends until more data arrives in the buffer. If FALSE,* the buffer is flushed without waiting, but this routine * returns immediately with an ID that can be used to kill the upload task.* Upload is done by spawning the task 'tWVUpload'. The buffer to upload is * identified by <bufId>, and the upload path to use is identified by <pathId>.** This routine blocks if no event data is in the buffer, so it should* be called before event logging is started to ensure the buffer does* not overflow.** RETURNS: A valid WV_UPLOADTASK_ID if started for continuous* upload, a non-NULL value if started for one-pass upload, and NULL * if the task can not be spawned or memory for the descriptor * can not be allocated.**/WV_UPLOADTASK_ID wvUploadStart ( BUFFER_ID bufId, /* event data buffer ID */ UPLOAD_ID pathId, /* upload path to host */ BOOL uploadContinuously /* upload continuously if true */ ) { WV_UPLOADTASK_ID upTaskId; /* returned to later identify the upload task */ /* Check for valid parameters. */ if (bufId == NULL || pathId == NULL) return (NULL); /* * Create and initialize the upload task descriptor to return to the * user. This id is necessary for stopping the task later. */ if ((upTaskId = (WV_UPLOADTASK_ID) malloc (sizeof (WV_UPLOADTASK_DESC))) == NULL) { logMsg ("wvUploadStart: can't alloc uploadTask id memory.\n", 0,0,0,0,0,0); return (NULL); } if (semBInit (& upTaskId->uploadCompleteSem, SEM_Q_PRIORITY, SEM_EMPTY) == ERROR) { logMsg ("wvUploadStart: can't init uploadTask sem.\n",0,0,0,0,0,0); return (NULL); } upTaskId->bufferId = bufId; upTaskId->uploadPathId = pathId; upTaskId->status = OK; if (uploadContinuously) upTaskId->exitWhenEmpty = FALSE; else upTaskId->exitWhenEmpty = TRUE; /* Now spawn the task. */ if ((upTaskId->uploadTaskId = taskSpawn ("tWVUpload", wvUploadTaskPriority, wvUploadTaskOptions, wvUploadTaskStackSize, wvUpload, (int) upTaskId, 0, 0, 0, 0, 0, 0, 0, 0, 0)) == ERROR) { logMsg ("wvUploadStart: can't spawn uploadTask.\n",0,0,0,0,0,0); return (NULL); } return (upTaskId); }/********************************************************************************* wvUploadStop - stop upload of events to host (WindView)** This routine stops continuous upload of events to the host. It does this* by making a request to the upload task to terminate after it has emptied* the buffer. For this reason it is important to make sure data is no* longer being logged to the buffer before calling this routine.* * This task blocks until the buffer is emptied, and then frees memory* associated with <upTaskId>.** RETURNS: OK if the upload task terminates successfully, * or ERROR either if <upTaskId> is invalid or if the upload task terminates* with an ERROR.**/STATUS wvUploadStop ( WV_UPLOADTASK_ID upTaskId ) { STATUS retStatus; if (upTaskId == NULL) return (ERROR); /* * Ask the upload task to flush the buffer and then exit. The upload * task may have emptied the buffer and be waiting on the buffer's * threshold-crossed semaphore, so we give that semaphore so the task * won't pend forever. */ upTaskId->exitWhenEmpty = TRUE; semGive (& upTaskId->bufferId->threshXSem); /* Wait for flushing to complete, but only if uploader worked correctly */ if (upTaskId->status == OK) semTake (& upTaskId->uploadCompleteSem, WAIT_FOREVER); /* Free up the memory associated with the upload descriptor. */ semTerminate (& upTaskId->uploadCompleteSem); retStatus = upTaskId->status; free (upTaskId); return (retStatus); }/*******************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -