Skip to content
This repository was archived by the owner on Jul 29, 2024. It is now read-only.

Commit ac85a15

Browse files
authored
Fix EB_ENC_PD_ERROR4/8 in race conditions (#580)
- Race condition 1 in PA happens in this way: EbGetEmptyObject(queue, &p); EbObjectIncLiveCount(&p, 1); EbReleaseObject(&p) EbObjectIncLiveCount(&p, 1); //bug, increase live count after release EbReleaseObject(&p) //bug, double release Fix in this way: EbGetEmptyObject(queue, &p); EbObjectIncLiveCount(&p, 2); //increase by 2 directly EbReleaseObject(&p) EbReleaseObject(&p) - Race condition 2 in PD and ENC: ENC call EbReleaseObject() before PD call EbObjectIncLiveCount(1) in other words: dependentPicturesCount-- before dependentPicturesCount++, so as that dependentPicturesCount become negative e.g. -1 another race condition: ++/-- is NOT thread safe, dependentPicturesCount ++/-- happen at same time so that this counter cannot go back to zero, leads to the queue entry will never be released, queue full, 0x2103 error Fix in this way: first remove the useless pair of EbReleaseObject and EbObjectIncLiveCount and then workaround: force remove the entries that stay in the queue for unreasonable long time even dependentPicturesCount is not reduced to zero Signed-off-by: xiaoxime <[email protected]>
1 parent b5587b0 commit ac85a15

File tree

5 files changed

+29
-32
lines changed

5 files changed

+29
-32
lines changed

Source/Lib/Codec/EbEncDecProcess.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3231,15 +3231,11 @@ void* EncDecKernel(void *inputPtr)
32313231
if (((pictureControlSetPtr->sliceType == EB_P_PICTURE) || (pictureControlSetPtr->sliceType == EB_B_PICTURE)) &&
32323232
pictureControlSetPtr->ParentPcsPtr->refPaPcsArray[REF_LIST_0]) {
32333233
((EbPaReferenceObject_t *)pictureControlSetPtr->ParentPcsPtr->refPaPcsArray[REF_LIST_0]->paReferencePictureWrapperPtr->objectPtr)->dependentPicturesCount--;
3234-
EbReleaseObject(pictureControlSetPtr->ParentPcsPtr->refPaPcsArray[REF_LIST_0]->paReferencePictureWrapperPtr);
3235-
EbReleaseObject(pictureControlSetPtr->ParentPcsPtr->refPaPcsArray[REF_LIST_0]->pPcsWrapperPtr);
32363234
}
32373235

32383236
if ((pictureControlSetPtr->sliceType == EB_B_PICTURE) &&
32393237
pictureControlSetPtr->ParentPcsPtr->refPaPcsArray[REF_LIST_1]) {
32403238
((EbPaReferenceObject_t *)pictureControlSetPtr->ParentPcsPtr->refPaPcsArray[REF_LIST_1]->paReferencePictureWrapperPtr->objectPtr)->dependentPicturesCount--;
3241-
EbReleaseObject(pictureControlSetPtr->ParentPcsPtr->refPaPcsArray[REF_LIST_1]->paReferencePictureWrapperPtr);
3242-
EbReleaseObject(pictureControlSetPtr->ParentPcsPtr->refPaPcsArray[REF_LIST_1]->pPcsWrapperPtr);
32433239
}
32443240

32453241
// Note: release the PPCS and its PA reference picture in both EncDec and RateControl

Source/Lib/Codec/EbPictureDecisionProcess.c

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,17 +1234,8 @@ void* PictureDecisionKernel(void *inputPtr)
12341234
pictureControlSetPtr->refPicPocArray[REF_LIST_0] = refPoc;
12351235
pictureControlSetPtr->refPaPcsArray[REF_LIST_0] = paReferenceEntryPtr->pPcsPtr;
12361236

1237-
// Increment the PA Reference's liveCount by the number of tiles in the input picture
1238-
EbObjectIncLiveCount(
1239-
paReferenceEntryPtr->inputObjectPtr,
1240-
1);
1241-
12421237
((EbPaReferenceObject_t*)pictureControlSetPtr->refPaPicPtrArray[REF_LIST_0]->objectPtr)->pPcsPtr = paReferenceEntryPtr->pPcsPtr;
12431238

1244-
EbObjectIncLiveCount(
1245-
paReferenceEntryPtr->pPcsPtr->pPcsWrapperPtr,
1246-
1);
1247-
12481239
--paReferenceEntryPtr->dependentCount;
12491240
((EbPaReferenceObject_t *)paReferenceEntryPtr->pPcsPtr->paReferencePictureWrapperPtr->objectPtr)->dependentPicturesCount++;
12501241
}
@@ -1270,17 +1261,8 @@ void* PictureDecisionKernel(void *inputPtr)
12701261
pictureControlSetPtr->refPaPicPtrArray[REF_LIST_1] = paReferenceEntryPtr->inputObjectPtr;
12711262
pictureControlSetPtr->refPicPocArray[REF_LIST_1] = refPoc;
12721263

1273-
// Increment the PA Reference's liveCount by the number of tiles in the input picture
1274-
EbObjectIncLiveCount(
1275-
paReferenceEntryPtr->inputObjectPtr,
1276-
1);
1277-
12781264
((EbPaReferenceObject_t*)pictureControlSetPtr->refPaPicPtrArray[REF_LIST_1]->objectPtr)->pPcsPtr = paReferenceEntryPtr->pPcsPtr;
12791265

1280-
EbObjectIncLiveCount(
1281-
paReferenceEntryPtr->pPcsPtr->pPcsWrapperPtr,
1282-
1);
1283-
12841266
--paReferenceEntryPtr->dependentCount;
12851267
((EbPaReferenceObject_t*)paReferenceEntryPtr->pPcsPtr->paReferencePictureWrapperPtr->objectPtr)->dependentPicturesCount++;
12861268
}
@@ -1353,6 +1335,16 @@ void* PictureDecisionKernel(void *inputPtr)
13531335
if (((EbPaReferenceObject_t *)inputEntryPtr->pPcsPtr->paReferencePictureWrapperPtr->objectPtr)->dependentPicturesCount == 0) {
13541336
inputEntryPtr->inputObjectPtr = (EbObjectWrapper_t *)EB_NULL;
13551337
}
1338+
else {
1339+
// TODO sometimes dependentPicturesCount never returns zero, due to ++/-- is NOT thread safe
1340+
// Force remove the entry, if it was BLOCKED (due to dependentPicturesCount != 0) in the queue for NOT reasonable long time
1341+
EB_S32 qlen = (EB_S32)encodeContextPtr->pictureDecisionPaReferenceQueueTailIndex - (EB_S32)encodeContextPtr->pictureDecisionPaReferenceQueueHeadIndex;
1342+
if (qlen < 0) qlen += PICTURE_DECISION_PA_REFERENCE_QUEUE_MAX_DEPTH;
1343+
if (qlen > PRE_ASSIGNMENT_MAX_DEPTH) {
1344+
// SVT_LOG("Warning: force remove a blocked item from pictureDecisionPaReferenceQueue \n");
1345+
inputEntryPtr->inputObjectPtr = (EbObjectWrapper_t *)EB_NULL;
1346+
}
1347+
}
13561348
}
13571349

13581350
// Increment the HeadIndex if the head is null

Source/Lib/Codec/EbReferenceObject.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ typedef struct EbPaReferenceObject_s {
5454
EB_U8 yMean[MAX_NUMBER_OF_TREEBLOCKS_PER_PICTURE];
5555
EB_PICTURE sliceType;
5656

57-
EB_U32 dependentPicturesCount; //number of pic using this reference frame
57+
EB_S32 dependentPicturesCount; //number of pic using this reference frame
5858
PictureParentControlSet_t *pPcsPtr;
5959
} EbPaReferenceObject_t;
6060

Source/Lib/Codec/EbResourceCoordinationProcess.c

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ void* ResourceCoordinationKernel(void *inputPtr)
472472
// Parent PCS is released by the Rate Control after passing through MDC->MD->ENCDEC->Packetization
473473
EbObjectIncLiveCount(
474474
pictureControlSetWrapperPtr,
475-
1);
475+
2);
476476

477477
pictureControlSetPtr = (PictureParentControlSet_t*) pictureControlSetWrapperPtr->objectPtr;
478478

@@ -605,16 +605,11 @@ void* ResourceCoordinationKernel(void *inputPtr)
605605
pictureControlSetPtr->paReferencePictureWrapperPtr = referencePictureWrapperPtr;
606606

607607
// Note: the PPCS and its PA reference picture will be released in both EncDec and RateControl kernels.
608-
// Give the new Reference a nominal liveCount of 2, meanwhile increase liveCount of PPCS with 1 as it's
609-
// already 1 after dequeuing from the PPCS FIFO.
608+
// Give the new Reference a nominal liveCount of 2
610609
EbObjectIncLiveCount(
611610
pictureControlSetPtr->paReferencePictureWrapperPtr,
612611
2);
613612

614-
EbObjectIncLiveCount(
615-
pictureControlSetWrapperPtr,
616-
1);
617-
618613
// Get Empty Output Results Object
619614
// Note: record the PCS object into output of the Resource Coordination process for EOS frame(s).
620615
// Because EbH265GetPacket() can get the encoded bit stream only if Packetization process has

Source/Lib/Codec/EbSystemResourceManager.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,13 +388,20 @@ EB_ERRORTYPE EbObjectIncLiveCount(
388388
EbObjectWrapper_t *wrapperPtr,
389389
EB_U32 incrementNumber)
390390
{
391+
EB_ERRORTYPE return_error = EB_ErrorNone;
392+
391393
EbBlockOnMutex(wrapperPtr->systemResourcePtr->emptyQueue->lockoutMutex);
392394

393-
wrapperPtr->liveCount += incrementNumber;
395+
if (wrapperPtr->liveCount == EB_ObjectWrapperReleasedValue) {
396+
SVT_LOG("Warning: %p is already released. Ignored the EbObjectIncLiveCount(%d) call \n", wrapperPtr, incrementNumber);
397+
return_error = EB_ErrorBadParameter;
398+
} else {
399+
wrapperPtr->liveCount += incrementNumber;
400+
}
394401

395402
EbReleaseMutex(wrapperPtr->systemResourcePtr->emptyQueue->lockoutMutex);
396403

397-
return EB_ErrorNone;
404+
return return_error;
398405
}
399406

400407
//ugly hack
@@ -429,6 +436,7 @@ static EB_ERRORTYPE EBObjectWrapperCtor(EbObjectWrapper_t* wrapper,
429436
wrapper->dctor = EBObjectWrapperDctor;
430437
wrapper->releaseEnable = EB_TRUE;
431438
wrapper->quitSignal = EB_FALSE;
439+
wrapper->liveCount = 0;
432440
wrapper->systemResourcePtr = resource;
433441
wrapper->objectDestroyer = objectDestroyer;
434442
ret = objectCreator(&wrapper->objectPtr, objectInitDataPtr);
@@ -597,6 +605,12 @@ EB_ERRORTYPE EbReleaseObject(
597605

598606
EbBlockOnMutex(objectPtr->systemResourcePtr->emptyQueue->lockoutMutex);
599607

608+
if (objectPtr->liveCount == EB_ObjectWrapperReleasedValue) {
609+
SVT_LOG("Warning: %p is already released. Ignored the double EbReleaseObject() call \n", objectPtr);
610+
EbReleaseMutex(objectPtr->systemResourcePtr->emptyQueue->lockoutMutex);
611+
return EB_ErrorBadParameter;
612+
}
613+
600614
// Decrement liveCount
601615
objectPtr->liveCount = (objectPtr->liveCount == 0) ? objectPtr->liveCount : objectPtr->liveCount - 1;
602616

0 commit comments

Comments
 (0)