static rc_t BAMReaderThreadMain(KThread const *const th, void *const vp) { BAMReader *const self = (BAMReader *)vp; rc_t rc = 0; const BAMAlignment* rec; KLockAcquire(self->lock); do { while (self->nque == BUFFER_COUNT) KConditionWait(self->need_data, self->lock); { rc = BAMFileRead( self->file, &rec); if (rc == END_OF_DATA) { rec = NULL; rc = 0; } else if (rc) break; self->que[self->nque] = rec; ++self->nque; KConditionSignal(self->have_data); } } while (rec); self->rc = rc; KLockUnlock(self->lock); return 0; }
/* Whack */ rc_t VCursorWhack ( VCursor *self ) { #if VCURSOR_FLUSH_THREAD if ( self -> flush_thread != NULL ) { rc_t rc = KLockAcquire ( self -> flush_lock ); if ( rc == 0 ) { while ( self -> flush_state == vfBusy ) { MTCURSOR_DBG (( "VCursorWhack: waiting for thread to process\n" )); KConditionWait ( self -> flush_cond, self -> flush_lock ); } self -> flush_state = vfExit; KConditionSignal ( self -> flush_cond ); KLockUnlock ( self -> flush_lock ); } MTCURSOR_DBG (( "VCursorWhack: waiting on thread to exit\n" )); KThreadWait ( self -> flush_thread, NULL ); } MTCURSOR_DBG (( "VCursorWhack: finishing\n" )); KThreadRelease ( self -> flush_thread ); KConditionRelease ( self -> flush_cond ); KLockRelease ( self -> flush_lock ); #endif VCursorTerminatePagemapThread(self); return VCursorDestroy ( self ); }
/* Free * signal that resources have become available */ LIB_EXPORT rc_t CC KSemaphoreFree ( KSemaphore *self, uint64_t count ) { if ( self == NULL ) return RC ( rcPS, rcSemaphore, rcSignaling, rcSelf, rcNull ); self -> avail += count; if ( self -> waiting != 0 && self -> avail >= self -> min_requested ) { /* whacky logic - if everyone has requested the same amount - and only one request can be satisfied - then signal. otherwise, broadcast */ if ( self -> uniform && self -> avail / self -> min_requested == 1 ) return KConditionSignal ( self -> cond ); return KConditionBroadcast ( self -> cond ); } return 0; }
/* Read * read an aligment * * "result" [ OUT ] - return param for BAMAlignment object * must be released with BAMAlignmentRelease * * returns RC(..., ..., ..., rcRow, rcNotFound) at end */ rc_t BAMReaderRead ( const BAMReader *cself, const BAMAlignment **result ) { rc_t rc; BAMReader *self = (BAMReader *)cself; if (self == NULL) return RC(rcAlign, rcFile, rcReading, rcParam, rcNull); if (self->eof) return RC(rcAlign, rcFile, rcReading, rcData, rcInsufficient); KLockAcquire(self->lock); if ((rc = self->rc) == 0) { while (self->nque == 0 && (rc = self->rc) == 0) KConditionWait(self->have_data, self->lock); if (rc == 0) { *result = self->que[0]; if (*result) { --self->nque; memmove(&self->que[0], &self->que[1], self->nque * sizeof(self->que[0])); KConditionSignal(self->need_data); } else { self->eof = true; rc = END_OF_DATA; } } } KLockUnlock(self->lock); return rc; }
static rc_t VCursorFlushPageInt ( VCursor *self ) { rc_t rc; if ( self == NULL ) rc = RC ( rcVDB, rcCursor, rcFlushing, rcSelf, rcNull ); else if ( self -> read_only ) rc = RC ( rcVDB, rcCursor, rcFlushing, rcCursor, rcReadonly ); else { int64_t end_id; #if ! VCURSOR_FLUSH_THREAD run_trigger_prod_data pb; #endif switch ( self -> state ) { case vcConstruct: rc = RC ( rcVDB, rcCursor, rcFlushing, rcCursor, rcNotOpen ); break; case vcFailed: rc = RC ( rcVDB, rcCursor, rcFlushing, rcCursor, rcInvalid ); break; case vcRowOpen: rc = RC ( rcVDB, rcCursor, rcFlushing, rcCursor, rcBusy ); break; default: /* ignore request if there is no page to commit */ if ( self -> start_id == self -> end_id ) { /* the cursor should be in unwritten state, where the row_id can be reset but drags along the other markers. */ assert ( self -> end_id == self -> row_id ); return 0; } #if VCURSOR_FLUSH_THREAD MTCURSOR_DBG (( "VCursorFlushPageInt: going to acquire lock\n" )); /* get lock */ rc = KLockAcquire ( self -> flush_lock ); if ( rc != 0 ) return rc; MTCURSOR_DBG (( "VCursorFlushPageInt: have lock\n" )); /* make sure that background thread is ready */ while ( self -> flush_state == vfBusy ) { MTCURSOR_DBG (( "VCursorFlushPageInt: waiting for background thread\n" )); rc = KConditionWait ( self -> flush_cond, self -> flush_lock ); if ( rc != 0 ) { LOGERR ( klogSys, rc, "VCursorFlushPageInt: wait failed - exiting" ); KLockUnlock ( self -> flush_lock ); return rc; } } if ( self -> flush_state != vfReady ) { if ( self -> flush_state != vfBgErr ) rc = RC ( rcVDB, rcCursor, rcFlushing, rcCursor, rcInconsistent ); else { rc_t rc2; MTCURSOR_DBG (( "VCursorFlushPageInt: waiting on thread to exit\n" )); rc = KThreadWait ( self -> flush_thread, & rc2 ); if ( rc == 0 ) { rc = rc2; MTCURSOR_DBG (( "VCursorFlushPageInt: releasing thread\n" )); KThreadRelease ( self -> flush_thread ); self -> flush_thread = NULL; } } PLOGERR ( klogInt, (klogInt, rc, "VCursorFlushPageInt: not in ready state[$(state)] - exiting","state=%hu",self -> flush_state )); KLockUnlock ( self -> flush_lock ); return rc; } MTCURSOR_DBG (( "VCursorFlushPageInt: running buffer page\n" )); #endif /* first, tell all columns to bundle up their pages into buffers */ end_id = self -> end_id; rc = RC ( rcVDB, rcCursor, rcFlushing, rcMemory, rcExhausted ); if ( VectorDoUntil ( & self -> row, false, WColumnBufferPage, & end_id ) ) { VectorForEach ( & self -> row, false, WColumnDropPage, NULL ); self -> flush_state = vfFgErr; } else { /* supposed to be constant */ assert ( end_id == self -> end_id ); #if VCURSOR_FLUSH_THREAD MTCURSOR_DBG (( "VCursorFlushPageInt: pages buffered - capturing id and count\n" )); self -> flush_id = self -> start_id; self -> flush_cnt = self -> end_id - self -> start_id; self -> start_id = self -> end_id; self -> end_id = self -> row_id + 1; self -> state = vcReady; MTCURSOR_DBG (( "VCursorFlushPageInt: state set to busy - signaling bg thread\n" )); self -> flush_state = vfBusy; rc = KConditionSignal ( self -> flush_cond ); if ( rc != 0 ) LOGERR ( klogSys, rc, "VCursorFlushPageInt: condition returned error on signal" ); #else /* run all validation and trigger productions */ pb . id = self -> start_id; pb . cnt = self -> end_id - self -> start_id; pb . rc = 0; if ( ! VectorDoUntil ( & self -> trig, false, run_trigger_prods, & pb ) ) { self -> start_id = self -> end_id; self -> end_id = self -> row_id + 1; self -> state = vcReady; } rc = pb . rc; /* drop page buffers */ VectorForEach ( & self -> row, false, WColumnDropPage, NULL ); #endif } #if VCURSOR_FLUSH_THREAD MTCURSOR_DBG (( "VCursorFlushPageInt: unlocking\n" )); KLockUnlock ( self -> flush_lock ); #endif } } return rc; }
static rc_t CC run_flush_thread ( const KThread *t, void *data ) { rc_t rc; VCursor *self = data; /* acquire lock */ MTCURSOR_DBG (( "run_flush_thread: acquiring lock\n" )); rc = KLockAcquire ( self -> flush_lock ); if ( rc == 0 ) { do { bool failed; run_trigger_prod_data pb; /* wait for data */ if ( self -> flush_state == vfReady ) { MTCURSOR_DBG (( "run_flush_thread: waiting for input\n" )); rc = KConditionWait ( self -> flush_cond, self -> flush_lock ); if ( rc != 0 ) break; } /* bail unless state is busy */ if ( self -> flush_state != vfBusy ) { MTCURSOR_DBG (( "run_flush_thread: exiting\n" )); break; } /* prepare param block */ pb . id = self -> flush_id; pb . cnt = self -> flush_cnt; pb . rc = 0; MTCURSOR_DBG (( "run_flush_thread: unlocking and running\n" )); KLockUnlock ( self -> flush_lock ); /* run productions from trigger roots */ failed = VectorDoUntil ( & self -> trig, false, run_trigger_prods, & pb ); /* drop page buffers */ MTCURSOR_DBG (( "run_flush_thread: dropping page buffers\n" )); VectorForEach ( & self -> row, false, WColumnDropPage, NULL ); /* reacquire lock */ MTCURSOR_DBG (( "run_flush_thread: re-acquiring lock" )); rc = KLockAcquire ( self -> flush_lock ); if ( rc != 0 ) { self -> flush_state = vfBgErr; LOGERR ( klogSys, rc, "run_flush_thread: re-acquiring lock failed - exit" ); return rc; } #if FORCE_FLUSH_ERROR_EXIT if ( ! failed ) { pb . rc = RC ( rcVDB, rcCursor, rcFlushing, rcThread, rcCanceled ); failed = true; } #endif /* get out on failure */ if ( failed ) { self -> flush_state = vfBgErr; LOGERR ( klogInt, pb . rc, "run_flush_thread: run_trigger_prods failed - exit" ); KConditionSignal ( self -> flush_cond ); rc = pb . rc; } /* no longer busy */ else if ( self -> flush_state == vfBusy ) { /* signal waiter */ self -> flush_state = vfReady; MTCURSOR_DBG (( "run_flush_thread: signaling ready\n" )); rc = KConditionSignal ( self -> flush_cond ); if ( rc != 0 ) LOGERR ( klogSys, rc, "run_flush_thread: failed to signal foreground thread - exit" ); } } while ( rc == 0 ); MTCURSOR_DBG (( "run_flush_thread: unlocking\n" )); KLockUnlock ( self -> flush_lock ); } MTCURSOR_DBG (( "run_flush_thread: exit\n" )); return rc; }