From c481e28e6880be55092e0b3352e4e3adc2de79dc Mon Sep 17 00:00:00 2001 From: Aravindan NC <35158113+AravindanNC@users.noreply.github.com> Date: Wed, 15 Apr 2026 14:26:22 -0400 Subject: [PATCH 1/7] Update profile.c --- source/bulkdata/profile.c | 152 +++++++++++++++++++------------------- 1 file changed, 77 insertions(+), 75 deletions(-) diff --git a/source/bulkdata/profile.c b/source/bulkdata/profile.c index 1b0cf593..1f0b2d1b 100644 --- a/source/bulkdata/profile.c +++ b/source/bulkdata/profile.c @@ -54,7 +54,7 @@ static bool initialized = false; static Vector *profileList; -static pthread_mutex_t plMutex; +static pthread_rwlock_t profileListLock; // L0: protects profileList (rdlock for reads, wrlock for writes) static pthread_mutex_t reportLock; static pthread_mutex_t triggerConditionQueMutex = PTHREAD_MUTEX_INITIALIZER; @@ -207,6 +207,7 @@ static void freeProfile(void *data) cJSON_Delete(profile->jsonReportObj); profile->jsonReportObj = NULL; } + pthread_mutex_destroy(&profile->profileMutex); free(profile); } T2Debug("%s ++out \n", __FUNCTION__); @@ -302,19 +303,19 @@ T2ERROR profileWithNameExists(const char *profileName, bool *bProfileExists) *bProfileExists = false; return T2ERROR_FAILURE; } - pthread_mutex_lock(&plMutex); + pthread_rwlock_rdlock(&profileListLock); for(; profileIndex < Vector_Size(profileList); profileIndex++) { tempProfile = (Profile *)Vector_At(profileList, profileIndex); if(strcmp(tempProfile->name, profileName) == 0) { *bProfileExists = true; - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); return T2ERROR_SUCCESS; } } *bProfileExists = false; - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); T2Error("Profile with Name : %s not found\n", profileName); return T2ERROR_PROFILE_NOT_FOUND; } @@ -925,17 +926,17 @@ reportThreadEnd : void NotifyTimeout(const char* profileName, bool isClearSeekMap) { T2Debug("%s ++in\n", __FUNCTION__); - pthread_mutex_lock(&plMutex); + pthread_rwlock_rdlock(&profileListLock); Profile *profile = NULL; if(T2ERROR_SUCCESS != getProfile(profileName, &profile)) { T2Error("Profile : %s not found\n", profileName); - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); return ; } - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); T2Info("%s: profile %s is in %s state\n", __FUNCTION__, profileName, profile->enable ? "Enabled" : "Disabled"); pthread_mutex_lock(&profile->reportInProgressMutex); if(profile->enable && !profile->reportInProgress) @@ -975,15 +976,15 @@ T2ERROR Profile_storeMarkerEvent(const char *profileName, T2Event *eventInfo) { T2Debug("%s ++in\n", __FUNCTION__); - pthread_mutex_lock(&plMutex); + pthread_rwlock_rdlock(&profileListLock); Profile *profile = NULL; if(T2ERROR_SUCCESS != getProfile(profileName, &profile)) { T2Error("Profile : %s not found\n", profileName); - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); return T2ERROR_FAILURE; } - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); if(!profile->enable) { T2Warning("Profile : %s is disabled, ignoring the event\n", profileName); @@ -1138,10 +1139,11 @@ T2ERROR addProfile(Profile *profile) T2Error("profile list is not initialized yet, ignoring\n"); return T2ERROR_FAILURE; } - pthread_mutex_lock(&plMutex); + pthread_mutex_init(&profile->profileMutex, NULL); + pthread_rwlock_wrlock(&profileListLock); Vector_PushBack(profileList, profile); - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); T2Debug("%s --out\n", __FUNCTION__); return T2ERROR_SUCCESS; } @@ -1154,18 +1156,18 @@ T2ERROR enableProfile(const char *profileName) T2Error("profile list is not initialized yet, ignoring\n"); return T2ERROR_FAILURE; } - pthread_mutex_lock(&plMutex); + pthread_rwlock_rdlock(&profileListLock); Profile *profile = NULL; if(T2ERROR_SUCCESS != getProfile(profileName, &profile)) { T2Error("Profile : %s not found\n", profileName); - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); return T2ERROR_FAILURE; } if(profile->enable) { T2Info("Profile : %s is already enabled - ignoring duplicate request\n", profileName); - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); return T2ERROR_SUCCESS; } else @@ -1174,19 +1176,19 @@ T2ERROR enableProfile(const char *profileName) if(pthread_mutex_init(&profile->triggerCondMutex, NULL) != 0) { T2Error(" %s Mutex init has failed\n", __FUNCTION__); - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); return T2ERROR_FAILURE; } if(pthread_mutex_init(&profile->reportInProgressMutex, NULL) != 0) { T2Error(" %s Mutex init has failed\n", __FUNCTION__); - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); return T2ERROR_FAILURE; } if(pthread_cond_init(&profile->reportInProgressCond, NULL) != 0) { T2Error(" %s Cond init has failed\n", __FUNCTION__); - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); return T2ERROR_FAILURE; } @@ -1201,7 +1203,7 @@ T2ERROR enableProfile(const char *profileName) { profile->enable = false; T2Error("Unable to register profile : %s with Scheduler\n", profileName); - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); return T2ERROR_FAILURE; } T2ER_StartDispatchThread(); @@ -1209,7 +1211,7 @@ T2ERROR enableProfile(const char *profileName) T2Info("Successfully enabled profile : %s\n", profileName); } T2Debug("%s --out\n", __FUNCTION__); - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); return T2ERROR_SUCCESS; } @@ -1221,7 +1223,7 @@ void updateMarkerComponentMap() size_t profileIndex = 0; Profile *tempProfile = NULL; - pthread_mutex_lock(&plMutex); + pthread_rwlock_rdlock(&profileListLock); for(; profileIndex < Vector_Size(profileList); profileIndex++) { tempProfile = (Profile *)Vector_At(profileList, profileIndex); @@ -1237,7 +1239,7 @@ void updateMarkerComponentMap() } } } - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); T2Debug("%s --out\n", __FUNCTION__); } @@ -1251,12 +1253,12 @@ T2ERROR disableProfile(const char *profileName, bool *isDeleteRequired) return T2ERROR_FAILURE; } - pthread_mutex_lock(&plMutex); + pthread_rwlock_rdlock(&profileListLock); Profile *profile = NULL; if(T2ERROR_SUCCESS != getProfile(profileName, &profile)) { T2Error("Profile : %s not found\n", profileName); - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); return T2ERROR_FAILURE; } @@ -1272,7 +1274,7 @@ T2ERROR disableProfile(const char *profileName, bool *isDeleteRequired) removeProfileFromDisk(SEEKFOLDER, profile->name); #endif profile->isSchedulerstarted = false; - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); T2Debug("%s --out\n", __FUNCTION__); return T2ERROR_SUCCESS; @@ -1286,24 +1288,24 @@ T2ERROR deleteAllProfiles(bool delFromDisk) int profileIndex = 0; Profile *tempProfile = NULL; - pthread_mutex_lock(&plMutex); + pthread_rwlock_wrlock(&profileListLock); if(profileList == NULL) { T2Error("profile list is not initialized yet or profileList is empty, ignoring\n"); - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); return T2ERROR_FAILURE; } count = Vector_Size(profileList); - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); for(; profileIndex < count; profileIndex++) { - pthread_mutex_lock(&plMutex); + pthread_rwlock_rdlock(&profileListLock); tempProfile = (Profile *)Vector_At(profileList, profileIndex); tempProfile->enable = false; tempProfile->isSchedulerstarted = false; - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); if(T2ERROR_SUCCESS != unregisterProfileFromScheduler(tempProfile->name)) { @@ -1330,13 +1332,13 @@ T2ERROR deleteAllProfiles(bool delFromDisk) * after setting threadExists = false (see CollectAndReport cleanup). */ } - /* Re-acquire plMutex for profile cleanup */ - pthread_mutex_lock(&plMutex); + /* Re-acquire profileListLock for profile cleanup */ + pthread_rwlock_rdlock(&profileListLock); if(tempProfile->grepSeekProfile) { freeGrepSeekProfile(tempProfile->grepSeekProfile); } - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); if(delFromDisk == true) { removeProfileFromDisk(REPORTPROFILES_PERSISTENCE_PATH, tempProfile->name); @@ -1350,12 +1352,12 @@ T2ERROR deleteAllProfiles(bool delFromDisk) removeProfileFromDisk(REPORTPROFILES_PERSISTENCE_PATH, MSGPACK_REPORTPROFILES_PERSISTENT_FILE); } - pthread_mutex_lock(&plMutex); + pthread_rwlock_wrlock(&profileListLock); T2Debug("Deleting all profiles from the profileList\n"); Vector_Destroy(profileList, freeProfile); profileList = NULL; Vector_Create(&profileList); - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); T2Debug("%s --out\n", __FUNCTION__); @@ -1366,17 +1368,17 @@ bool isProfileEnabled(const char *profileName) { bool is_profile_enable = false; Profile *get_profile = NULL; - pthread_mutex_lock(&plMutex); + pthread_rwlock_rdlock(&profileListLock); if(T2ERROR_SUCCESS != getProfile(profileName, &get_profile)) { T2Error("Profile : %s not found\n", profileName); T2Debug("%s --out\n", __FUNCTION__); - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); return false; } is_profile_enable = get_profile->enable; T2Debug("is_profile_enable = %d \n", is_profile_enable); - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); return is_profile_enable; } @@ -1391,11 +1393,11 @@ T2ERROR deleteProfile(const char *profileName) } Profile *profile = NULL; - pthread_mutex_lock(&plMutex); + pthread_rwlock_rdlock(&profileListLock); if(T2ERROR_SUCCESS != getProfile(profileName, &profile)) { T2Error("Profile : %s not found\n", profileName); - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); return T2ERROR_FAILURE; } @@ -1407,14 +1409,14 @@ T2ERROR deleteProfile(const char *profileName) { profile->isSchedulerstarted = false; } - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); if(T2ERROR_SUCCESS != unregisterProfileFromScheduler(profileName)) { T2Info("Profile : %s already removed from scheduler\n", profileName); } T2Info("Waiting for CollectAndReport to be complete : %s\n", profileName); - pthread_mutex_lock(&plMutex); + pthread_rwlock_rdlock(&profileListLock); // Wait for any in-progress report to finish under reportInProgressMutex. // threadExists must NOT be read here — it is written under reuseThreadMutex @@ -1435,13 +1437,13 @@ T2ERROR deleteProfile(const char *profileName) bool threadStillExists = profile->threadExists; pthread_mutex_unlock(&profile->reuseThreadMutex); - /* Release plMutex before pthread_join to avoid deadlock. + /* Release profileListLock before pthread_join to avoid deadlock. * pthread_join can block indefinitely if the CollectAndReport thread - * is stuck (e.g., waiting on rbusMethodMutex). Holding plMutex during + * is stuck (e.g., waiting on rbusMethodMutex). Holding profileListLock during * pthread_join prevents other threads (timeout callbacks, other profile * operations) from making progress, creating a deadlock. */ - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); if (threadStillExists) { @@ -1454,8 +1456,8 @@ T2ERROR deleteProfile(const char *profileName) * after setting threadExists = false (see CollectAndReport cleanup). */ } - /* Re-acquire plMutex for profile cleanup operations */ - pthread_mutex_lock(&plMutex); + /* Re-acquire profileListLock (wrlock) for profile cleanup operations */ + pthread_rwlock_wrlock(&profileListLock); if(Vector_Size(profile->triggerConditionList) > 0) { @@ -1476,7 +1478,7 @@ T2ERROR deleteProfile(const char *profileName) #endif Vector_RemoveItem(profileList, profile, freeProfile); - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); T2Debug("%s --out\n", __FUNCTION__); return T2ERROR_SUCCESS; } @@ -1487,7 +1489,7 @@ void sendLogUploadInterruptToScheduler() Profile *tempProfile = NULL; T2Debug("%s ++in\n", __FUNCTION__); - pthread_mutex_lock(&plMutex); + pthread_rwlock_rdlock(&profileListLock); for(; profileIndex < Vector_Size(profileList); profileIndex++) { tempProfile = (Profile *)Vector_At(profileList, profileIndex); @@ -1496,7 +1498,7 @@ void sendLogUploadInterruptToScheduler() SendInterruptToTimeoutThread(tempProfile->name); } } - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); T2Debug("%s --out\n", __FUNCTION__); } @@ -1640,9 +1642,9 @@ T2ERROR initProfileList(bool checkPreviousSeek) return T2ERROR_SUCCESS; } initialized = true; - if(pthread_mutex_init(&plMutex, NULL) != 0) + if(pthread_rwlock_init(&profileListLock, NULL) != 0) { - T2Error("%s mutex init has failed\n", __FUNCTION__); + T2Error("%s rwlock init has failed\n", __FUNCTION__); return T2ERROR_FAILURE; } if(pthread_mutex_init(&reportLock, NULL) != 0 ) @@ -1651,9 +1653,9 @@ T2ERROR initProfileList(bool checkPreviousSeek) return T2ERROR_FAILURE; } - pthread_mutex_lock(&plMutex); + pthread_rwlock_wrlock(&profileListLock); Vector_Create(&profileList); - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); registerConditionalReportCallBack(&triggerReportOnCondtion); @@ -1672,9 +1674,9 @@ int getProfileCount() T2Info("profile list isn't initialized\n"); return count; } - pthread_mutex_lock(&plMutex); + pthread_rwlock_rdlock(&profileListLock); count = Vector_Size(profileList); - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); T2Debug("%s --out\n", __FUNCTION__); return count; @@ -1687,7 +1689,7 @@ hash_map_t *getProfileHashMap() Profile *tempProfile = NULL; T2Debug("%s ++in\n", __FUNCTION__); - pthread_mutex_lock(&plMutex); + pthread_rwlock_rdlock(&profileListLock); profileHashMap = hash_map_create(); for(; profileIndex < Vector_Size(profileList); profileIndex++) { @@ -1696,7 +1698,7 @@ hash_map_t *getProfileHashMap() char *profileHash = strdup(tempProfile->hash); hash_map_put(profileHashMap, profileName, profileHash, free); } - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); T2Debug("%s --out\n", __FUNCTION__); return profileHashMap; @@ -1726,7 +1728,7 @@ T2ERROR uninitProfileList() } pthread_mutex_destroy(&reportLock); - pthread_mutex_destroy(&plMutex); + pthread_rwlock_destroy(&profileListLock); T2Debug("%s --out\n", __FUNCTION__); return T2ERROR_SUCCESS; @@ -1746,7 +1748,7 @@ T2ERROR registerTriggerConditionConsumer() while(retry_count <= MAX_RETRY_COUNT) { - pthread_mutex_lock(&plMutex); + pthread_rwlock_rdlock(&profileListLock); profileIndex = 0; for(; profileIndex < Vector_Size(profileList); profileIndex++) { @@ -1762,7 +1764,7 @@ T2ERROR registerTriggerConditionConsumer() } } - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); if(retry == 1) { if(retry_count >= MAX_RETRY_COUNT) @@ -1788,8 +1790,8 @@ void NotifySchedulerstart(char* profileName, bool isschedulerstarted) { size_t profileIndex = 0; Profile *tempProfile = NULL; - pthread_mutex_lock(&plMutex); - T2Debug("plMutex is locked %s\n", __FUNCTION__); + pthread_rwlock_rdlock(&profileListLock); + T2Debug("profileListLock is rdlocked %s\n", __FUNCTION__); for(; profileIndex < Vector_Size(profileList); profileIndex++) { tempProfile = (Profile *)Vector_At(profileList, profileIndex); @@ -1801,8 +1803,8 @@ void NotifySchedulerstart(char* profileName, bool isschedulerstarted) } } } - pthread_mutex_unlock(&plMutex); - T2Debug("plMutex is unlocked %s\n", __FUNCTION__); + pthread_rwlock_unlock(&profileListLock); + T2Debug("profileListLock is unlocked %s\n", __FUNCTION__); return; } @@ -1954,7 +1956,7 @@ T2ERROR triggerReportOnCondtion(const char *referenceName, const char *reference size_t j, profileIndex = 0; Profile *tempProfile = NULL; - pthread_mutex_lock(&plMutex); + pthread_rwlock_rdlock(&profileListLock); for(; profileIndex < Vector_Size(profileList); profileIndex++) { tempProfile = (Profile *)Vector_At(profileList, profileIndex); @@ -1976,9 +1978,9 @@ T2ERROR triggerReportOnCondtion(const char *referenceName, const char *reference char *tempProfilename = strdup(tempProfile->name); //RDKB-42640 - // plmutex should be unlocked before sending interrupt for report generation - T2Debug("%s : Release lock on &plMutex\n ", __FUNCTION__); - pthread_mutex_unlock(&plMutex); + // profileListLock should be unlocked before sending interrupt for report generation + T2Debug("%s : Release lock on &profileListLock\n ", __FUNCTION__); + pthread_rwlock_unlock(&profileListLock); T2Info("Triggering report on condition for %s with %s operator, %d threshold\n", triggerCondition->reference, triggerCondition->oprator, triggerCondition->threshold); if(tempProfile->isSchedulerstarted) @@ -1999,8 +2001,8 @@ T2ERROR triggerReportOnCondtion(const char *referenceName, const char *reference else { T2Info("Report generation will take place by popping up from the que by callback function \n"); - T2Debug("%s : Release lock on &plMutex\n ", __FUNCTION__); - pthread_mutex_unlock(&plMutex); + T2Debug("%s : Release lock on &profileListLock\n ", __FUNCTION__); + pthread_rwlock_unlock(&profileListLock); return T2ERROR_SUCCESS; } } @@ -2008,7 +2010,7 @@ T2ERROR triggerReportOnCondtion(const char *referenceName, const char *reference } } } - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); T2Debug("%s --out\n", __FUNCTION__); return T2ERROR_SUCCESS; } @@ -2018,18 +2020,18 @@ unsigned int getMinThresholdDuration(char *profileName) unsigned int minThresholdDuration = 0; Profile *get_profile = NULL; T2Debug("%s --in\n", __FUNCTION__); - pthread_mutex_lock(&plMutex); + pthread_rwlock_rdlock(&profileListLock); if(T2ERROR_SUCCESS != getProfile(profileName, &get_profile)) { T2Error("Profile : %s not found\n", profileName); T2Debug("%s --out\n", __FUNCTION__); - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); return 0; } minThresholdDuration = get_profile->minThresholdDuration; get_profile->minThresholdDuration = 0; // reinit the value T2Debug("minThresholdDuration = %u \n", minThresholdDuration); - pthread_mutex_unlock(&plMutex); + pthread_rwlock_unlock(&profileListLock); T2Debug("%s --out\n", __FUNCTION__); return minThresholdDuration; } From c1026d888fc0b08ebc43fe7493bedc8f0efd7b37 Mon Sep 17 00:00:00 2001 From: Aravindan NC <35158113+AravindanNC@users.noreply.github.com> Date: Wed, 15 Apr 2026 14:26:55 -0400 Subject: [PATCH 2/7] Update profile.h --- source/bulkdata/profile.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/source/bulkdata/profile.h b/source/bulkdata/profile.h index 21bd4de4..948b5782 100644 --- a/source/bulkdata/profile.h +++ b/source/bulkdata/profile.h @@ -39,6 +39,20 @@ typedef struct _JSONEncoding TimeStampFormat tsFormat; } JSONEncoding; +/** + * Lock Hierarchy (acquire in ascending order to prevent deadlocks): + * L0: profileListLock (module-level rwlock - protects profileList) + * L1: profileMutex (per-profile - protects profile state) + * L2: reuseThreadMutex (per-profile - protects thread lifecycle) + * L3: reportInProgressMutex (per-profile - protects reportInProgress flag) + * L4: triggerCondMutex / eventMutex / reportMutex (per-profile - leaf locks) + * + * Rules: + * - Always acquire L0 before L1, L1 before L2, etc. + * - Never hold a higher-numbered lock when acquiring a lower-numbered lock. + * - profileListLock uses rdlock for lookups/iterations, wrlock for add/remove. + * - Release profileListLock before long operations (pthread_join, HTTP send). + */ typedef struct _Profile { bool enable; @@ -94,6 +108,7 @@ typedef struct _Profile bool restartRequested; bool threadExists; GrepSeekProfile *grepSeekProfile; // To store GrepConfig + pthread_mutex_t profileMutex; // L1: per-profile lock for state protection } Profile; T2ERROR initProfileList(bool checkPreviousSeek); From 1225eabeaf33f399e4d20082f27d30cf0a58b9e6 Mon Sep 17 00:00:00 2001 From: Aravindan NC <35158113+AravindanNC@users.noreply.github.com> Date: Wed, 15 Apr 2026 14:27:27 -0400 Subject: [PATCH 3/7] Update profilexconf.c --- source/bulkdata/profilexconf.c | 153 +++++++++++++++++---------------- 1 file changed, 79 insertions(+), 74 deletions(-) diff --git a/source/bulkdata/profilexconf.c b/source/bulkdata/profilexconf.c index 3a8e8424..f3250d91 100644 --- a/source/bulkdata/profilexconf.c +++ b/source/bulkdata/profilexconf.c @@ -45,7 +45,12 @@ static bool initialized = false; static ProfileXConf *singleProfile = NULL; -static pthread_mutex_t plMutex; /* TODO - we can remove plMutex most likely but firseck that CollectAndReport doesn't cause issue */ +/** + * xconfProfileLock: Protects singleProfile pointer and reportThreadExits flag. + * Kept as mutex (not rwlock) because pthread_cond_wait requires pthread_mutex_t. + * Lock hierarchy: L0 (same level as profileListLock in profile.c). + */ +static pthread_mutex_t xconfProfileLock; static pthread_cond_t reuseThread; static bool reportThreadExits = false; @@ -209,16 +214,16 @@ static void* CollectAndReportXconf(void* data) (void) data;// To fix compiler warning /* Set reportThreadExits flag under mutex to prevent data race with - * ProfileXConf_notifyTimeout which reads this flag under plMutex. + * ProfileXConf_notifyTimeout which reads this flag under xconfProfileLock. */ - pthread_mutex_lock(&plMutex); + pthread_mutex_lock(&xconfProfileLock); reportThreadExits = true; - pthread_mutex_unlock(&plMutex); + pthread_mutex_unlock(&xconfProfileLock); do { - /* CRITICAL SECTION START: Acquire plMutex to check/access singleProfile */ - pthread_mutex_lock(&plMutex); + /* CRITICAL SECTION START: Acquire xconfProfileLock to check/access singleProfile */ + pthread_mutex_lock(&xconfProfileLock); T2Info("%s while Loop -- START \n", __FUNCTION__); if(singleProfile == NULL) @@ -231,7 +236,7 @@ static void* CollectAndReportXconf(void* data) /* Set reportInProgress flag to prevent concurrent report generation * and profile deletion while we're working. This must be done under - * plMutex to prevent races with ProfileXConf_notifyTimeout() and + * xconfProfileLock to prevent races with ProfileXConf_notifyTimeout() and * ProfileXConf_delete(). */ profile->reportInProgress = true; @@ -257,21 +262,21 @@ static void* CollectAndReportXconf(void* data) T2Info("%s ++in profileName : %s\n", __FUNCTION__, profile->name); } - /* CRITICAL: Release plMutex before potentially blocking operations. + /* CRITICAL: Release xconfProfileLock before potentially blocking operations. * Report generation involves: * - * Holding plMutex during these operations blocks ALL other XCONF profile + * Holding xconfProfileLock during these operations blocks ALL other XCONF profile * operations (timeouts, updates, deletions, marker events) system-wide, * causing the telemetry system to hang. * - * We can safely release plMutex here because: + * We can safely release xconfProfileLock here because: * 1. We've already checked singleProfile is valid * 2. We use profile->reportInProgress to prevent concurrent reports * 3. Profile deletion waits for reportInProgress to be false - * 4. We'll re-acquire plMutex before updating shared state + * 4. We'll re-acquire xconfProfileLock before updating shared state */ - pthread_mutex_unlock(&plMutex); - /* CRITICAL SECTION END - plMutex released, other threads can now proceed */ + pthread_mutex_unlock(&xconfProfileLock); + /* CRITICAL SECTION END - xconfProfileLock released, other threads can now proceed */ int clockReturn = 0; clockReturn = clock_gettime(CLOCK_MONOTONIC, &startTime); @@ -280,11 +285,11 @@ static void* CollectAndReportXconf(void* data) if(T2ERROR_SUCCESS != initJSONReportXconf(&profile->jsonReportObj, &valArray)) { T2Error("Failed to initialize JSON Report\n"); - /* Re-acquire plMutex before updating profile state. - * CRITICAL: Keep plMutex locked before goto because reportXconfThreadEnd + /* Re-acquire xconfProfileLock before updating profile state. + * CRITICAL: Keep xconfProfileLock locked before goto because reportXconfThreadEnd * calls pthread_cond_wait which requires the mutex to be locked. */ - pthread_mutex_lock(&plMutex); + pthread_mutex_lock(&xconfProfileLock); if(singleProfile == profile) { profile->reportInProgress = false; @@ -331,19 +336,19 @@ static void* CollectAndReportXconf(void* data) dcaFlagReportCompleation(); - /* CRITICAL: Re-acquire plMutex to safely access eMarkerList. + /* CRITICAL: Re-acquire xconfProfileLock to safely access eMarkerList. * External components can call t2_event_s() which modifies eMarkerList - * via ProfileXConf_storeMarkerEvent(). We must hold plMutex during + * via ProfileXConf_storeMarkerEvent(). We must hold xconfProfileLock during * event marker encoding to prevent race conditions. * This is safe because encoding is quick (~milliseconds), unlike HTTP * upload which can take 30+ seconds. */ - pthread_mutex_lock(&plMutex); + pthread_mutex_lock(&xconfProfileLock); if(singleProfile == profile && profile->eMarkerList != NULL && Vector_Size(profile->eMarkerList) > 0) { encodeEventMarkersInJSON(valArray, profile->eMarkerList); } - pthread_mutex_unlock(&plMutex); + pthread_mutex_unlock(&xconfProfileLock); profile->grepSeekProfile->execCounter += 1; T2Info("Xconf Profile Execution Count = %d\n", profile->grepSeekProfile->execCounter); @@ -364,11 +369,11 @@ static void* CollectAndReportXconf(void* data) if(ret != T2ERROR_SUCCESS) { T2Error("Unable to generate report for : %s\n", profile->name); - /* Re-acquire plMutex before updating profile state. - * CRITICAL: Keep plMutex locked before goto because reportXconfThreadEnd + /* Re-acquire xconfProfileLock before updating profile state. + * CRITICAL: Keep xconfProfileLock locked before goto because reportXconfThreadEnd * calls pthread_cond_wait which requires the mutex to be locked. */ - pthread_mutex_lock(&plMutex); + pthread_mutex_lock(&xconfProfileLock); if(singleProfile == profile) { profile->reportInProgress = false; @@ -400,11 +405,11 @@ static void* CollectAndReportXconf(void* data) // Before caching the report, add "REPORT_TYPE": "CACHED" // tagReportAsCached(&jsonReport); Vector_PushBack(profile->cachedReportList, strdup(jsonReport)); - /* Re-acquire plMutex before updating profile state. - * CRITICAL: Keep plMutex locked before goto because reportXconfThreadEnd + /* Re-acquire xconfProfileLock before updating profile state. + * CRITICAL: Keep xconfProfileLock locked before goto because reportXconfThreadEnd * calls pthread_cond_wait which requires the mutex to be locked. */ - pthread_mutex_lock(&plMutex); + pthread_mutex_lock(&xconfProfileLock); if(singleProfile == profile) { profile->reportInProgress = false; @@ -555,11 +560,11 @@ static void* CollectAndReportXconf(void* data) isAbortTriggered = false ; } - /* CRITICAL SECTION START: Re-acquire plMutex before updating profile state. - * pthread_cond_wait requires us to hold plMutex, so we acquire it here + /* CRITICAL SECTION START: Re-acquire xconfProfileLock before updating profile state. + * pthread_cond_wait requires us to hold xconfProfileLock, so we acquire it here * and hold it through the state update and into the cond_wait. */ - pthread_mutex_lock(&plMutex); + pthread_mutex_lock(&xconfProfileLock); if(singleProfile == profile) { profile->reportInProgress = false; @@ -573,26 +578,26 @@ reportXconfThreadEnd : * Wait while: profile exists AND no timeout pending AND not shutting down. * Exit loop when: timeout arrives (reportInProgress=true) OR shutdown (initialized=false). * - * pthread_cond_wait atomically releases plMutex while waiting. - * When signaled or spuriously woken, it re-acquires plMutex before returning. + * pthread_cond_wait atomically releases xconfProfileLock while waiting. + * When signaled or spuriously woken, it re-acquires xconfProfileLock before returning. */ while(singleProfile && !singleProfile->reportInProgress && initialized) { - pthread_cond_wait(&reuseThread, &plMutex); + pthread_cond_wait(&reuseThread, &xconfProfileLock); } - /* After cond_wait loop exits, we hold plMutex again. Release it before + /* After cond_wait loop exits, we hold xconfProfileLock again. Release it before * the next loop iteration (which will re-acquire it). */ - pthread_mutex_unlock(&plMutex); + pthread_mutex_unlock(&xconfProfileLock); } while(initialized); - /* Thread is exiting. We don't hold plMutex here, so acquire it to + /* Thread is exiting. We don't hold xconfProfileLock here, so acquire it to * update the reportThreadExits flag, then release it. */ - pthread_mutex_lock(&plMutex); + pthread_mutex_lock(&xconfProfileLock); reportThreadExits = false; - pthread_mutex_unlock(&plMutex); + pthread_mutex_unlock(&xconfProfileLock); T2Info("%s --out exiting the CollectAndReportXconf thread \n", __FUNCTION__); return NULL; @@ -608,7 +613,7 @@ T2ERROR ProfileXConf_init(bool checkPreviousSeek) Config *config = NULL; initialized = true; - if(pthread_mutex_init(&plMutex, NULL) != 0) + if(pthread_mutex_init(&xconfProfileLock, NULL) != 0) { T2Error("%s Mutex init has failed\n", __FUNCTION__); return T2ERROR_FAILURE; @@ -619,7 +624,7 @@ T2ERROR ProfileXConf_init(bool checkPreviousSeek) if(pthread_cond_init(&reuseThread, NULL) != 0) { T2Error("%s Condition variable init has failed\n", __FUNCTION__); - pthread_mutex_destroy(&plMutex); + pthread_mutex_destroy(&xconfProfileLock); return T2ERROR_FAILURE; } Vector_Create(&configList); @@ -693,22 +698,22 @@ T2ERROR ProfileXConf_uninit() if(reportInProgress) { T2Debug("Waiting for final report before uninit\n"); - pthread_mutex_lock(&plMutex); + pthread_mutex_lock(&xconfProfileLock); pthread_cond_signal(&reuseThread); - pthread_mutex_unlock(&plMutex); + pthread_mutex_unlock(&xconfProfileLock); pthread_join(singleProfile->reportThread, NULL); pthread_mutex_lock(&singleProfile->reportInProgressMutex); singleProfile->reportInProgress = false ; pthread_mutex_unlock(&singleProfile->reportInProgressMutex); T2Info("Final report is completed, releasing profile memory\n"); } - pthread_mutex_lock(&plMutex); + pthread_mutex_lock(&xconfProfileLock); freeProfileXConf(); - pthread_mutex_unlock(&plMutex); + pthread_mutex_unlock(&xconfProfileLock); /* Destroy condition variable at module uninit, after all threads are stopped */ pthread_cond_destroy(&reuseThread); - pthread_mutex_destroy(&plMutex); + pthread_mutex_destroy(&xconfProfileLock); T2Debug("%s --out\n", __FUNCTION__); return T2ERROR_SUCCESS; } @@ -719,7 +724,7 @@ T2ERROR ProfileXConf_set(ProfileXConf *profile) T2ERROR ret = T2ERROR_FAILURE; - pthread_mutex_lock(&plMutex); + pthread_mutex_lock(&xconfProfileLock); if(!singleProfile) { @@ -735,11 +740,11 @@ T2ERROR ProfileXConf_set(ProfileXConf *profile) addT2EventMarker(eMarker->markerName, eMarker->compName, singleProfile->name, eMarker->skipFreq); } - /* Release plMutex before calling scheduler API to avoid potential + /* Release xconfProfileLock before calling scheduler API to avoid potential * blocking while holding the mutex. Scheduler operations may involve * timer management and other operations that shouldn't block profile access. */ - pthread_mutex_unlock(&plMutex); + pthread_mutex_unlock(&xconfProfileLock); if(registerProfileWithScheduler(singleProfile->name, singleProfile->reportingInterval, INFINITE_TIMEOUT, false, true, false, DEFAULT_FIRST_REPORT_INT, NULL) == T2ERROR_SUCCESS) { @@ -751,15 +756,15 @@ T2ERROR ProfileXConf_set(ProfileXConf *profile) T2Error("Unable to register profile : %s with Scheduler\n", singleProfile->name); } - /* Note: We already released plMutex above, so no need to unlock again */ - pthread_mutex_lock(&plMutex); + /* Note: We already released xconfProfileLock above, so no need to unlock again */ + pthread_mutex_lock(&xconfProfileLock); } else { T2Error("XConf profile already added, can't have more then 1 profile\n"); } - pthread_mutex_unlock(&plMutex); + pthread_mutex_unlock(&xconfProfileLock); T2Debug("%s --out\n", __FUNCTION__); return ret; @@ -775,7 +780,7 @@ void ProfileXConf_updateMarkerComponentMap() } size_t emIndex = 0; EventMarker *eMarker = NULL; - pthread_mutex_lock(&plMutex); + pthread_mutex_lock(&xconfProfileLock); if(singleProfile) { for(; emIndex < Vector_Size(singleProfile->eMarkerList); emIndex++) @@ -788,14 +793,14 @@ void ProfileXConf_updateMarkerComponentMap() { T2Error("Profile not found in %s\n", __FUNCTION__); } - pthread_mutex_unlock(&plMutex); + pthread_mutex_unlock(&xconfProfileLock); T2Debug("%s --out\n", __FUNCTION__); } bool ProfileXConf_isNameEqual(char* profileName) { bool isName = false; - pthread_mutex_lock(&plMutex); + pthread_mutex_lock(&xconfProfileLock); if(initialized) { if(singleProfile && (singleProfile->name != NULL) && (profileName != NULL) && !strcmp(singleProfile->name, profileName)) //Adding NULL check to avoid strcmp crash @@ -805,7 +810,7 @@ bool ProfileXConf_isNameEqual(char* profileName) } } - pthread_mutex_unlock(&plMutex); + pthread_mutex_unlock(&xconfProfileLock); return isName; } @@ -820,23 +825,23 @@ T2ERROR ProfileXConf_delete(ProfileXConf *profile) T2Debug("calling ProfileXConf_isNameEqual function form %s and line %d\n", __FUNCTION__, __LINE__); bool isNameEqual = ProfileXConf_isNameEqual(profile->name); - pthread_mutex_lock(&plMutex); + pthread_mutex_lock(&xconfProfileLock); if(!singleProfile) { T2Error("Profile not found in %s\n", __FUNCTION__); - pthread_mutex_unlock(&plMutex); + pthread_mutex_unlock(&xconfProfileLock); return T2ERROR_FAILURE; } /* Copy profile name before unlocking to prevent use-after-free if - * another thread deletes/frees singleProfile after we release plMutex. + * another thread deletes/frees singleProfile after we release xconfProfileLock. */ char profileNameCopy[256] = {0}; if(!isNameEqual && singleProfile && singleProfile->name) { strncpy(profileNameCopy, singleProfile->name, sizeof(profileNameCopy) - 1); } - pthread_mutex_unlock(&plMutex); + pthread_mutex_unlock(&xconfProfileLock); if(isNameEqual) { @@ -849,7 +854,7 @@ T2ERROR ProfileXConf_delete(ProfileXConf *profile) else { /* Use copied profile name instead of singleProfile->name to avoid - * use-after-free since we no longer hold plMutex. + * use-after-free since we no longer hold xconfProfileLock. */ if(profileNameCopy[0] != '\0') { @@ -865,7 +870,7 @@ T2ERROR ProfileXConf_delete(ProfileXConf *profile) * causing use-after-free crash when CollectAndReportXconf() was still * accessing profile members during brief mutex holds (event encoding, etc). */ - pthread_mutex_lock(&plMutex); + pthread_mutex_lock(&xconfProfileLock); unsigned int waitIterations = 0; const unsigned int LOG_INTERVAL = 3000; // Log every 3000 iterations (30 seconds at 10ms per iteration) while(singleProfile && singleProfile->reportInProgress) @@ -875,9 +880,9 @@ T2ERROR ProfileXConf_delete(ProfileXConf *profile) T2Info("Waiting for CollectAndReportXconf to be complete : %s\n", singleProfile->name); } waitIterations++; - pthread_mutex_unlock(&plMutex); + pthread_mutex_unlock(&xconfProfileLock); usleep(10000); // 10ms polling interval - pthread_mutex_lock(&plMutex); + pthread_mutex_lock(&xconfProfileLock); } profile->reportThread = singleProfile->reportThread; @@ -989,7 +994,7 @@ T2ERROR ProfileXConf_delete(ProfileXConf *profile) T2Info("removing profile : %s\n", singleProfile->name); freeProfileXConf(); - pthread_mutex_unlock(&plMutex); + pthread_mutex_unlock(&xconfProfileLock); T2Debug("%s --out\n", __FUNCTION__); return T2ERROR_SUCCESS; } @@ -997,7 +1002,7 @@ T2ERROR ProfileXConf_delete(ProfileXConf *profile) bool ProfileXConf_isSet() { bool isSet = false; - pthread_mutex_lock(&plMutex); + pthread_mutex_lock(&xconfProfileLock); if(singleProfile != NULL) { @@ -1005,14 +1010,14 @@ bool ProfileXConf_isSet() isSet = true; } - pthread_mutex_unlock(&plMutex); + pthread_mutex_unlock(&xconfProfileLock); return isSet; } char* ProfileXconf_getName() { char* profileName = NULL ; - pthread_mutex_lock(&plMutex); + pthread_mutex_lock(&xconfProfileLock); if(initialized) { if(singleProfile) @@ -1020,7 +1025,7 @@ char* ProfileXconf_getName() profileName = strdup(singleProfile->name); } } - pthread_mutex_unlock(&plMutex); + pthread_mutex_unlock(&xconfProfileLock); return profileName; } @@ -1029,11 +1034,11 @@ void ProfileXConf_notifyTimeout(bool isClearSeekMap, bool isOnDemand) T2Debug("%s ++in\n", __FUNCTION__); int reportThreadStatus = 0 ; - pthread_mutex_lock(&plMutex); + pthread_mutex_lock(&xconfProfileLock); if(!singleProfile) { T2Error("Profile not found in %s\n", __FUNCTION__); - pthread_mutex_unlock(&plMutex); + pthread_mutex_unlock(&xconfProfileLock); return ; } isOnDemandReport = isOnDemand; @@ -1063,7 +1068,7 @@ void ProfileXConf_notifyTimeout(bool isClearSeekMap, bool isOnDemand) T2Warning("Received profileTimeoutCb while previous callback is still in progress - ignoring the request\n"); } - pthread_mutex_unlock(&plMutex); + pthread_mutex_unlock(&xconfProfileLock); T2Debug("%s --out\n", __FUNCTION__); } @@ -1073,11 +1078,11 @@ T2ERROR ProfileXConf_storeMarkerEvent(T2Event *eventInfo) { T2Debug("%s ++in\n", __FUNCTION__); - pthread_mutex_lock(&plMutex); + pthread_mutex_lock(&xconfProfileLock); if(!singleProfile) { T2Error("Profile not found in %s\n", __FUNCTION__); - pthread_mutex_unlock(&plMutex); + pthread_mutex_unlock(&xconfProfileLock); return T2ERROR_FAILURE; } @@ -1138,11 +1143,11 @@ T2ERROR ProfileXConf_storeMarkerEvent(T2Event *eventInfo) { T2Error("Event name : %s value : %s\n", eventInfo->name, eventInfo->value); T2Error("Event doens't match any marker information, shouldn't come here\n"); - pthread_mutex_unlock(&plMutex); + pthread_mutex_unlock(&xconfProfileLock); return T2ERROR_FAILURE; } - pthread_mutex_unlock(&plMutex); + pthread_mutex_unlock(&xconfProfileLock); T2Debug("%s --out\n", __FUNCTION__); return T2ERROR_SUCCESS; From f209d43156bf474b2f2e159d4b38a895aee3230f Mon Sep 17 00:00:00 2001 From: Aravindan NC <35158113+AravindanNC@users.noreply.github.com> Date: Wed, 15 Apr 2026 15:13:11 -0400 Subject: [PATCH 4/7] Update profile.c --- source/bulkdata/profile.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/bulkdata/profile.c b/source/bulkdata/profile.c index 1f0b2d1b..61dd9049 100644 --- a/source/bulkdata/profile.c +++ b/source/bulkdata/profile.c @@ -207,7 +207,6 @@ static void freeProfile(void *data) cJSON_Delete(profile->jsonReportObj); profile->jsonReportObj = NULL; } - pthread_mutex_destroy(&profile->profileMutex); free(profile); } T2Debug("%s ++out \n", __FUNCTION__); @@ -1139,7 +1138,6 @@ T2ERROR addProfile(Profile *profile) T2Error("profile list is not initialized yet, ignoring\n"); return T2ERROR_FAILURE; } - pthread_mutex_init(&profile->profileMutex, NULL); pthread_rwlock_wrlock(&profileListLock); Vector_PushBack(profileList, profile); @@ -1650,6 +1648,8 @@ T2ERROR initProfileList(bool checkPreviousSeek) if(pthread_mutex_init(&reportLock, NULL) != 0 ) { T2Error("%s mutex init has failed\n", __FUNCTION__); + pthread_rwlock_destroy(&profileListLock); + initialized = false; return T2ERROR_FAILURE; } From be4b2fbb320189189a7bcff65e4f96c095fba71d Mon Sep 17 00:00:00 2001 From: Aravindan NC <35158113+AravindanNC@users.noreply.github.com> Date: Wed, 15 Apr 2026 15:13:35 -0400 Subject: [PATCH 5/7] Update profile.c --- source/bulkdata/profile.c | 2141 +++---------------------------------- 1 file changed, 130 insertions(+), 2011 deletions(-) diff --git a/source/bulkdata/profile.c b/source/bulkdata/profile.c index 61dd9049..8401cf92 100644 --- a/source/bulkdata/profile.c +++ b/source/bulkdata/profile.c @@ -17,2023 +17,142 @@ * limitations under the License. */ +#ifndef _PROFILE_H_ +#define _PROFILE_H_ + #include -#include -#include -#include -#include -#include -#include +#include +#include -#include "profile.h" +#include "t2collection.h" +#include "telemetry2_0.h" #include "reportprofiles.h" #include "t2eventreceiver.h" -#include "t2markers.h" -#include "t2log_wrapper.h" -#include "busInterface.h" -#include "curlinterface.h" -#include "rbusmethodinterface.h" -#include "scheduler.h" -#include "persistence.h" +#include "t2common.h" #include "vector.h" -#include "dcautil.h" -#include "t2parser.h" -#include "rbusInterface.h" +#include "reportgen.h" #include "legacyutils.h" -#if defined(PRIVACYMODES_CONTROL) -#include "rdkservices_privacyutils.h" -#endif - -#define MAX_LEN 256 - -#ifdef GTEST_ENABLE -#define sendReportOverHTTP __wrap_sendReportOverHTTP -#define sendCachedReportsOverHTTP __wrap_sendCachedReportsOverHTTP -#endif - -static bool initialized = false; -static Vector *profileList; -static pthread_rwlock_t profileListLock; // L0: protects profileList (rdlock for reads, wrlock for writes) -static pthread_mutex_t reportLock; - -static pthread_mutex_t triggerConditionQueMutex = PTHREAD_MUTEX_INITIALIZER; -static queue_t *triggerConditionQueue = NULL; - -typedef struct __triggerConditionObj__ -{ - char referenceName[MAX_LEN]; - char referenceValue[MAX_LEN]; -} triggerConditionObj ; - -static void freeRequestURIparam(void *data) -{ - if(data != NULL) - { - HTTPReqParam *hparam = (HTTPReqParam *)data; - if(hparam->HttpName) - { - free(hparam->HttpName); - } - if(hparam->HttpRef) - { - free(hparam->HttpRef); - } - if(hparam->HttpValue) - { - free(hparam->HttpValue); - } - free(hparam); - } -} - -static void freeReportProfileConfig(void *data) -{ - if(data != NULL) - { - Config *config = (Config *)data; - - if(config->name) - { - free(config->name); - } - if(config->configData) - { - free(config->configData); - } - - free(config); - } -} - -static void freeProfile(void *data) -{ - T2Debug("%s ++in \n", __FUNCTION__); - if(data != NULL) - { - Profile *profile = (Profile *)data; - if(profile->name) - { - free(profile->name); - } - if(profile->hash) - { - free(profile->hash); - } - if(profile->protocol) - { - free(profile->protocol); - } - if(profile->encodingType) - { - free(profile->encodingType); - } - if(profile->RootName) - { - free(profile->RootName); - } - if(profile->Description) - { - free(profile->Description); - } - if(profile->version) - { - free(profile->version); - } - if(profile->jsonEncoding) - { - free(profile->jsonEncoding); - } - if(profile->timeRef) - { - free(profile->timeRef); - } - if(profile->t2HTTPDest) - { - free(profile->t2HTTPDest->URL); - if(profile->t2HTTPDest->RequestURIparamList) - { - Vector_Destroy(profile->t2HTTPDest->RequestURIparamList, freeRequestURIparam); - } - free(profile->t2HTTPDest); - } - if(profile->t2RBUSDest) - { - if(profile->t2RBUSDest->rbusMethodName) - { - memset(profile->t2RBUSDest->rbusMethodName, 0, strlen(profile->t2RBUSDest->rbusMethodName)); - free(profile->t2RBUSDest->rbusMethodName); - profile->t2RBUSDest->rbusMethodName = NULL ; - } - if(profile->t2RBUSDest->rbusMethodParamList) - { - // TBD determine whether data is simple string before passing free as cleanup function - Vector_Destroy(profile->t2RBUSDest->rbusMethodParamList, free); - } - free(profile->t2RBUSDest); - } - if(profile->eMarkerList) - { - Vector_Destroy(profile->eMarkerList, freeEMarker); - } - if(profile->gMarkerList) - { - Vector_Destroy(profile->gMarkerList, freeGMarker); - } - if(profile->topMarkerList) - { - Vector_Destroy(profile->topMarkerList, freeGMarker); - } - if(profile->paramList) - { - Vector_Destroy(profile->paramList, freeParam); - } - if (profile->staticParamList) - { - Vector_Destroy(profile->staticParamList, freeStaticParam); - } - if(profile->triggerConditionList) - { - Vector_Destroy(profile->triggerConditionList, freeTriggerCondition); - } - - if(profile->cachedReportList) - { - Vector_Destroy(profile->cachedReportList, free); - profile->cachedReportList = NULL; - } - if(profile->jsonReportObj) - { - cJSON_Delete(profile->jsonReportObj); - profile->jsonReportObj = NULL; - } - free(profile); - } - T2Debug("%s ++out \n", __FUNCTION__); -} - -static T2ERROR getProfile(const char *profileName, Profile **profile) -{ - size_t profileIndex = 0; - Profile *tempProfile = NULL; - T2Debug("%s ++in\n", __FUNCTION__); - if(profileName == NULL) - { - T2Error("profileName is null\n"); - return T2ERROR_FAILURE; - } - for(; profileIndex < Vector_Size(profileList); profileIndex++) - { - tempProfile = (Profile *)Vector_At(profileList, profileIndex); - if(strcmp(tempProfile->name, profileName) == 0) - { - *profile = tempProfile; - T2Debug("%s --out\n", __FUNCTION__); - return T2ERROR_SUCCESS; - } - } - T2Error("Profile with Name : %s not found\n", profileName); - return T2ERROR_PROFILE_NOT_FOUND; -} - -static T2ERROR initJSONReportProfile(cJSON** jsonObj, cJSON **valArray, char *rootname) -{ - *jsonObj = cJSON_CreateObject(); - if(*jsonObj == NULL) - { - T2Error("Failed to create cJSON object\n"); - return T2ERROR_FAILURE; - } - cJSON_AddItemToObject(*jsonObj, rootname, *valArray = cJSON_CreateArray()); - - - return T2ERROR_SUCCESS; -} - -static void calculateMaxUploadLatency(Profile *profile, time_t *maxuploadinmilliSec, time_t *maxuploadinSec) +typedef struct _JSONEncoding { - unsigned int random_value = 0; - // Ensure maxUploadLatency > 1 to avoid modulo by zero - if(profile->maxUploadLatency > 1) - { - int urandom = -1; - urandom = open("/dev/urandom", O_RDONLY); - if(urandom != -1 && read(urandom, &random_value, sizeof(random_value)) == sizeof(random_value)) - { - *maxuploadinmilliSec = random_value % (profile->maxUploadLatency - 1); - if(close(urandom) == -1) - { - T2Error("Failed to close /dev/urandom: %s\n", strerror(errno)); - } - } - else - { - if(urandom != -1) - { - if(close(urandom) == -1) - { - T2Error("Failed to close /dev/urandom: %s\n", strerror(errno)); - } - } - *maxuploadinmilliSec = (unsigned int)(time(0) % (profile->maxUploadLatency - 1)); - } - } - else - { - // If maxUploadLatency is 1, set maxuploadinmilliSec to 0 - *maxuploadinmilliSec = 0; - } - *maxuploadinSec = (*maxuploadinmilliSec + 1) / 1000; -} - -T2ERROR profileWithNameExists(const char *profileName, bool *bProfileExists) -{ - size_t profileIndex = 0; - Profile *tempProfile = NULL; - T2Debug("%s ++in\n", __FUNCTION__); - if(!initialized) - { - T2Error("profile list is not initialized yet, ignoring\n"); - return T2ERROR_FAILURE; - } - if(profileName == NULL) - { - T2Error("profileName is null\n"); - *bProfileExists = false; - return T2ERROR_FAILURE; - } - pthread_rwlock_rdlock(&profileListLock); - for(; profileIndex < Vector_Size(profileList); profileIndex++) - { - tempProfile = (Profile *)Vector_At(profileList, profileIndex); - if(strcmp(tempProfile->name, profileName) == 0) - { - *bProfileExists = true; - pthread_rwlock_unlock(&profileListLock); - return T2ERROR_SUCCESS; - } - } - *bProfileExists = false; - pthread_rwlock_unlock(&profileListLock); - T2Error("Profile with Name : %s not found\n", profileName); - return T2ERROR_PROFILE_NOT_FOUND; -} - -void getMarkerCompRbusSub(bool subscription) -{ - T2Debug("%s ++in\n", __FUNCTION__); - Vector* eventMarkerListForComponent = NULL; - getComponentMarkerList(T2REPORTCOMPONENT, (void**)&eventMarkerListForComponent); - int length = Vector_Size(eventMarkerListForComponent); - int i; - if(length > 0) - { - for(i = 0; i < length; ++i ) - { - char* markerName = (char *) Vector_At(eventMarkerListForComponent, i); - if(markerName) - { - int ret = T2RbusReportEventConsumer(markerName, subscription); - T2Debug("%d T2RbusEventReg with name = %s: subscription = %s ret %d \n", i, markerName, (subscription ? "Subscribe" : "Un-Subscribe"), ret); - } - else - { - T2Error("Error while retrieving Marker Name at index : %d \n", i); - } - } - if(eventMarkerListForComponent != NULL) - { - Vector_Destroy(eventMarkerListForComponent, free); - } - } - //CID 255490: Resource leak (RESOURCE_LEAK) - else - { - if(eventMarkerListForComponent != NULL) - { - Vector_Destroy(eventMarkerListForComponent, free); - } - } - T2Debug("%s --out\n", __FUNCTION__); -} - -static void* CollectAndReport(void* data) -{ - T2Debug("%s ++in\n", __FUNCTION__); - if(data == NULL) - { - T2Error("data passed is NULL can't identify the profile, existing from CollectAndReport\n"); - return NULL; - } - Profile* profile = (Profile *)data; - pthread_mutex_init(&profile->reuseThreadMutex, NULL); - pthread_cond_init(&profile->reuseThread, NULL); - pthread_mutex_lock(&profile->reuseThreadMutex); - profile->restartRequested = false; - profile->threadExists = true; - //GrepSeekProfile *GPF = profile->GrepSeekProfle; - do - { - T2Info("%s while Loop -- START \n", __FUNCTION__); - pthread_mutex_lock(&profile->reportInProgressMutex); - profile->reportInProgress = true; - pthread_cond_signal(&profile->reportInProgressCond); - pthread_mutex_unlock(&profile->reportInProgressMutex); - pthread_mutex_unlock(&profile->reuseThreadMutex); - - int count = profile->grepSeekProfile->execCounter; - - Vector *profileParamVals = NULL; - cJSON *valArray = NULL; - char* jsonReport = NULL; - cJSON *triggercondition = NULL; - time_t maxuploadinSec = 0; - time_t maxuploadinmilliSec = 0; - int n = 0; - struct timespec startTime; - struct timespec endTime; - struct timespec elapsedTime; - char* customLogPath = NULL; - int clockReturn = 0; - - T2ERROR ret = T2ERROR_FAILURE; - if( profile->name == NULL || profile->encodingType == NULL || profile->protocol == NULL ) - { - T2Error("Incomplete profile parameters\n"); - if(profile->triggerReportOnCondition) - { - T2Info(" Unlock trigger condition mutex and set report on condition to false \n"); - profile->triggerReportOnCondition = false ; - pthread_mutex_unlock(&profile->triggerCondMutex); - } - else - { - T2Debug(" profile->triggerReportOnCondition is not set \n"); - } - pthread_mutex_lock(&profile->reuseThreadMutex); - pthread_mutex_lock(&profile->reportInProgressMutex); - profile->reportInProgress = false; - pthread_cond_signal(&profile->reportInProgressCond); - pthread_mutex_unlock(&profile->reportInProgressMutex); - pthread_mutex_unlock(&profile->reuseThreadMutex); - //return NULL; - goto reportThreadEnd; - } - - T2Info("%s ++in profileName : %s\n", __FUNCTION__, profile->name); - - - clockReturn = clock_gettime(CLOCK_MONOTONIC, &startTime); - if( !strcmp(profile->encodingType, "JSON") || !strcmp(profile->encodingType, "MessagePack")) - { - JSONEncoding *jsonEncoding = profile->jsonEncoding; - if (jsonEncoding->reportFormat != JSONRF_KEYVALUEPAIR) - { - //TODO: Support 'ObjectHierarchy' format in RDKB-26154. - T2Error("Only JSON name-value pair format is supported \n"); - if(profile->triggerReportOnCondition) - { - T2Info(" Unlock trigger condition mutex and set report on condition to false \n"); - profile->triggerReportOnCondition = false ; - pthread_mutex_unlock(&profile->triggerCondMutex); - } - else - { - T2Debug(" profile->triggerReportOnCondition is not set \n"); - } - pthread_mutex_lock(&profile->reuseThreadMutex); - pthread_mutex_lock(&profile->reportInProgressMutex); - profile->reportInProgress = false; - pthread_cond_signal(&profile->reportInProgressCond); - pthread_mutex_unlock(&profile->reportInProgressMutex); - pthread_mutex_unlock(&profile->reuseThreadMutex); - //return NULL; - goto reportThreadEnd; - } - // pthread_mutex_lock(&profile->triggerCondMutex); - if(profile->triggerReportOnCondition && (profile->jsonReportObj != NULL)) - { - triggercondition = profile->jsonReportObj; - profile->jsonReportObj = NULL; - } - if(T2ERROR_SUCCESS != initJSONReportProfile(&profile->jsonReportObj, &valArray, profile->RootName)) - { - T2Error("Failed to initialize JSON Report\n"); - pthread_mutex_lock(&profile->reuseThreadMutex); - pthread_mutex_lock(&profile->reportInProgressMutex); - profile->reportInProgress = false; - pthread_cond_signal(&profile->reportInProgressCond); - pthread_mutex_unlock(&profile->reportInProgressMutex); - pthread_mutex_unlock(&profile->reuseThreadMutex); - //pthread_mutex_unlock(&profile->triggerCondMutex); - if(profile->triggerReportOnCondition) - { - T2Info(" Unlock trigger condition mutex and set report on condition to false \n"); - profile->triggerReportOnCondition = false; - pthread_mutex_unlock(&profile->triggerCondMutex); - if(profile->callBackOnReportGenerationComplete) - { - profile->callBackOnReportGenerationComplete(profile->name); - } - } - //return NULL; - goto reportThreadEnd; - } - else - { -#ifdef PERSIST_LOG_MON_REF - if(profile->checkPreviousSeek) - { - cJSON *arrayItem = NULL; - arrayItem = cJSON_CreateObject(); - cJSON_AddStringToObject(arrayItem, PREVIOUS_LOG, PREVIOUS_LOGS_VAL); - cJSON_AddItemToArray(valArray, arrayItem); - customLogPath = PREVIOUS_LOGS_PATH; - profile->bClearSeekMap = true; - T2Debug("Adding Previous Logs Header to JSON report\n"); - } -#endif - if(profile->staticParamList != NULL && Vector_Size(profile->staticParamList) > 0) - { - T2Debug(" Adding static Parameter Values to Json report\n"); - encodeStaticParamsInJSON(valArray, profile->staticParamList); - } - if(profile->paramList != NULL && Vector_Size(profile->paramList) > 0) - { - T2Debug("Fetching TR-181 Object/Parameter Values\n"); - profileParamVals = getProfileParameterValues(profile->paramList, count); - if(profileParamVals != NULL) - { - encodeParamResultInJSON(valArray, profile->paramList, profileParamVals); - } - Vector_Destroy(profileParamVals, freeProfileValues); - } - if(profile->topMarkerList != NULL && Vector_Size(profile->topMarkerList) > 0) - { - processTopPattern(profile->name, profile->topMarkerList, 0); - encodeTopResultInJSON(valArray, profile->topMarkerList); - } - if(profile->gMarkerList != NULL && Vector_Size(profile->gMarkerList) > 0) - { - getGrepResults(&(profile->grepSeekProfile), profile->gMarkerList, profile->bClearSeekMap, false, customLogPath); // Passing 4th argument as false so that it doesn't check rotated logs for the first reporting after bootup for multiprofiles. - encodeGrepResultInJSON(valArray, profile->gMarkerList); - } - if(profile->eMarkerList != NULL && Vector_Size(profile->eMarkerList) > 0) - { - pthread_mutex_lock(&profile->eventMutex); - encodeEventMarkersInJSON(valArray, profile->eMarkerList); - pthread_mutex_unlock(&profile->eventMutex); - } - if(profile->triggerReportOnCondition && (triggercondition != NULL)) - { - cJSON_AddItemToArray(valArray, triggercondition); - } - ret = prepareJSONReport(profile->jsonReportObj, &jsonReport); - destroyJSONReport(profile->jsonReportObj); - profile->jsonReportObj = NULL; - if(ret != T2ERROR_SUCCESS) - { - T2Error("Unable to generate report for : %s\n", profile->name); - pthread_mutex_lock(&profile->reuseThreadMutex); - pthread_mutex_lock(&profile->reportInProgressMutex); - profile->reportInProgress = false; - pthread_cond_signal(&profile->reportInProgressCond); - pthread_mutex_unlock(&profile->reportInProgressMutex); - pthread_mutex_unlock(&profile->reuseThreadMutex); - if(profile->triggerReportOnCondition) - { - profile->triggerReportOnCondition = false ; - pthread_mutex_unlock(&profile->triggerCondMutex); - - if(profile->callBackOnReportGenerationComplete) - { - profile->callBackOnReportGenerationComplete(profile->name); - } - } - else - { - T2Debug(" profile->triggerReportOnCondition is not set \n"); - } - //return NULL; - goto reportThreadEnd; - } -#ifdef PERSIST_LOG_MON_REF - if(profile->saveSeekConfig) - { - saveSeekConfigtoFile(profile->name, profile->grepSeekProfile); - } - if(profile->checkPreviousSeek) - { - T2Info("Previous Logs report is sent clear the previousSeek flag\n"); - profile->checkPreviousSeek = false; - customLogPath = NULL; - profile->bClearSeekMap = false; - } -#endif - long size = strlen(jsonReport); - T2Info("cJSON Report = %s\n", jsonReport); - cJSON *root = cJSON_Parse(jsonReport); - if(root != NULL) - { - cJSON *array = cJSON_GetObjectItem(root, profile->RootName); - if(cJSON_GetArraySize(array) == 0) - { - T2Warning("Array size of Report is %d. Report is empty. Cannot send empty report\n", cJSON_GetArraySize(array)); - pthread_mutex_lock(&profile->reuseThreadMutex); - pthread_mutex_lock(&profile->reportInProgressMutex); - profile->reportInProgress = false; - pthread_cond_signal(&profile->reportInProgressCond); - pthread_mutex_unlock(&profile->reportInProgressMutex); - pthread_mutex_unlock(&profile->reuseThreadMutex); - if(profile->triggerReportOnCondition) - { - T2Info(" Unlock trigger condition mutex and set report on condition to false \n"); - profile->triggerReportOnCondition = false ; - pthread_mutex_unlock(&profile->triggerCondMutex); - if(profile->callBackOnReportGenerationComplete) - { - profile->callBackOnReportGenerationComplete(profile->name); - } - } - else - { - T2Debug(" profile->triggerReportOnCondition is not set \n"); - } - cJSON_Delete(root); - //return NULL; - goto reportThreadEnd; - } - cJSON_Delete(root); - } - - T2Info("Report Size = %ld\n", size); - if(size > DEFAULT_MAX_REPORT_SIZE) - { - T2Warning("Report size is exceeding the max limit : %d\n", DEFAULT_MAX_REPORT_SIZE); - } - if(profile->maxUploadLatency > 0) - { - pthread_mutex_lock(&profile->reuseThreadMutex); - memset(&profile->maxlatencyTime, 0, sizeof(struct timespec)); - memset(&profile->currentTime, 0, sizeof(struct timespec)); - clock_gettime(CLOCK_REALTIME, &profile->currentTime); - profile->maxlatencyTime.tv_sec = profile->currentTime.tv_sec; - pthread_mutex_unlock(&profile->reuseThreadMutex); - pthread_mutex_init(&profile->reportMutex, NULL); - pthread_cond_init(&profile->reportcond, NULL); - calculateMaxUploadLatency(profile, &maxuploadinmilliSec, &maxuploadinSec); - } - if( strcmp(profile->protocol, "HTTP") == 0 || strcmp(profile->protocol, "RBUS_METHOD") == 0 ) - { - char *httpUrl = NULL ; - if ( strcmp(profile->protocol, "HTTP") == 0 ) - { - httpUrl = prepareHttpUrl(profile->t2HTTPDest); /* Append URL with http properties */ - if(profile->maxUploadLatency > 0) - { - T2Info("waiting for %ld sec of macUploadLatency\n", (long) maxuploadinSec); - struct timespec timeout; - pthread_mutex_lock(&profile->reuseThreadMutex); - profile->maxlatencyTime.tv_sec += maxuploadinSec; - timeout = profile->maxlatencyTime; - pthread_mutex_unlock(&profile->reuseThreadMutex); - pthread_mutex_lock(&profile->reportMutex); - while (profile->enable && n != ETIMEDOUT) - { - n = pthread_cond_timedwait(&profile->reportcond, &profile->reportMutex, &timeout); - } - if(n == ETIMEDOUT) - { - T2Info("TIMEOUT for maxUploadLatency of profile %s\n", profile->name); - ret = sendReportOverHTTP(httpUrl, jsonReport); - } - else if(n == 0) - { - T2Info("Profile : %s signaled before timeout, skipping report upload\n", profile->name); - } - else - { - T2Error("Profile : %s pthread_cond_timedwait ERROR!!!\n", profile->name); - pthread_mutex_unlock(&profile->reportMutex); - pthread_cond_destroy(&profile->reportcond); - if(httpUrl) - { - free(httpUrl); - httpUrl = NULL; - } - pthread_mutex_lock(&profile->reuseThreadMutex); - pthread_mutex_lock(&profile->reportInProgressMutex); - profile->reportInProgress = false; - pthread_cond_signal(&profile->reportInProgressCond); - pthread_mutex_unlock(&profile->reportInProgressMutex); - pthread_mutex_unlock(&profile->reuseThreadMutex); - if(profile->triggerReportOnCondition) - { - T2Info(" Unlock trigger condition mutex and set report on condition to false \n"); - profile->triggerReportOnCondition = false ; - pthread_mutex_unlock(&profile->triggerCondMutex); - - if(profile->callBackOnReportGenerationComplete != NULL) - { - T2Debug("Calling callback function profile->callBackOnReportGenerationComplete \n"); - profile->callBackOnReportGenerationComplete(profile->name); - } - } - else - { - T2Debug(" profile->triggerReportOnCondition is not set \n"); - } - //return NULL; - goto reportThreadEnd; - } - pthread_mutex_unlock(&profile->reportMutex); - pthread_cond_destroy(&profile->reportcond); - pthread_mutex_destroy(&profile->reportMutex); - } - else - { - ret = sendReportOverHTTP(httpUrl, jsonReport); - } - } - else - { - if(profile->maxUploadLatency > 0 ) - { - T2Info("waiting for %ld sec of macUploadLatency\n", (long) maxuploadinSec); - struct timespec timeout; - pthread_mutex_lock(&profile->reuseThreadMutex); - profile->maxlatencyTime.tv_sec += maxuploadinSec; - timeout = profile->maxlatencyTime; - pthread_mutex_unlock(&profile->reuseThreadMutex); - pthread_mutex_lock(&profile->reportMutex); - while (profile->enable && n != ETIMEDOUT) - { - n = pthread_cond_timedwait(&profile->reportcond, &profile->reportMutex, &timeout); - } - if(n == ETIMEDOUT) - { - T2Info("TIMEOUT for maxUploadLatency of profile %s\n", profile->name); - ret = sendReportsOverRBUSMethod(profile->t2RBUSDest->rbusMethodName, profile->t2RBUSDest->rbusMethodParamList, jsonReport); - } - else if(n == 0) - { - T2Info("Profile : %s signaled before timeout, skipping report upload\n", profile->name); - } - else - { - T2Error("Profile : %s pthread_cond_timedwait ERROR!!!\n", profile->name); - pthread_mutex_unlock(&profile->reportMutex); - pthread_cond_destroy(&profile->reportcond); - pthread_mutex_lock(&profile->reuseThreadMutex); - pthread_mutex_lock(&profile->reportInProgressMutex); - profile->reportInProgress = false; - pthread_cond_signal(&profile->reportInProgressCond); - pthread_mutex_unlock(&profile->reportInProgressMutex); - pthread_mutex_unlock(&profile->reuseThreadMutex); - if(profile->triggerReportOnCondition) - { - T2Info(" Unlock trigger condition mutex and set report on condition to false \n"); - profile->triggerReportOnCondition = false ; - pthread_mutex_unlock(&profile->triggerCondMutex); - - if(profile->callBackOnReportGenerationComplete) - { - T2Debug("Calling callback function profile->callBackOnReportGenerationComplete \n"); - profile->callBackOnReportGenerationComplete(profile->name); - } - } - else - { - T2Debug(" profile->triggerReportOnCondition is not set \n"); - } - //return NULL; - goto reportThreadEnd; - } - pthread_mutex_unlock(&profile->reportMutex); - pthread_cond_destroy(&profile->reportcond); - } - else - { - ret = sendReportsOverRBUSMethod(profile->t2RBUSDest->rbusMethodName, profile->t2RBUSDest->rbusMethodParamList, jsonReport); - } - } - if((ret == T2ERROR_FAILURE && strcmp(profile->protocol, "HTTP") == 0) || ret == T2ERROR_NO_RBUS_METHOD_PROVIDER) - { - T2Debug("Vector list size = %lu\n", (unsigned long) Vector_Size(profile->cachedReportList)); - if(profile->cachedReportList != NULL && Vector_Size(profile->cachedReportList) >= MAX_CACHED_REPORTS) - { - while(Vector_Size(profile->cachedReportList) > MAX_CACHED_REPORTS) - { - int pos = Vector_Size(profile->cachedReportList); - T2Info("Max Cached Reports Limit Exceeded, Removing the extra reports\n"); - char *extraCachedreport = (char*) Vector_At(profile->cachedReportList, (pos - 1)); - Vector_RemoveItem(profile->cachedReportList, (void*) extraCachedreport, NULL); - free(extraCachedreport); - } - T2Info("Max Cached Reports Limit Reached, Overwriting third recent report\n"); - char *thirdCachedReport = (char*) Vector_At(profile->cachedReportList, MAX_CACHED_REPORTS - 3); - Vector_RemoveItem(profile->cachedReportList, (void*) thirdCachedReport, NULL); - free(thirdCachedReport); - } - // Before caching the report, add "REPORT_TYPE": "CACHED" - tagReportAsCached(&jsonReport); - Vector_PushBack(profile->cachedReportList, jsonReport); - - T2Info("Report Cached, No. of reportes cached = %lu\n", (unsigned long )Vector_Size(profile->cachedReportList)); - // Save messages from profile->cachedReportList to a file in persistent location . - saveCachedReportToPersistenceFolder(profile->name, profile->cachedReportList); - - if(strcmp(profile->protocol, "RBUS_METHOD") == 0) - { - profile->SendErr++; - if(profile->SendErr > 3 && !(rbusCheckMethodExists(profile->t2RBUSDest->rbusMethodName))) //to delete the profile in the next CollectAndReport or triggercondition - { - T2Debug("RBUS_METHOD doesn't exists after 3 retries\n"); - pthread_mutex_lock(&profile->reuseThreadMutex); - pthread_mutex_lock(&profile->reportInProgressMutex); - profile->reportInProgress = false; - pthread_cond_signal(&profile->reportInProgressCond); - pthread_mutex_unlock(&profile->reportInProgressMutex); - pthread_mutex_unlock(&profile->reuseThreadMutex); - if(profile->triggerReportOnCondition) - { - profile->triggerReportOnCondition = false ; - pthread_mutex_unlock(&profile->triggerCondMutex); - if(profile->callBackOnReportGenerationComplete) - { - profile->callBackOnReportGenerationComplete(profile->name); - } - } - else - { - T2Debug(" profile->triggerReportOnCondition is not set \n"); - } - T2Error("ERROR: no method provider; profile will be deleted: %s %s\n", profile->name, - profile->t2RBUSDest->rbusMethodName); - if(T2ERROR_SUCCESS != deleteProfile(profile->name)) - { - T2Error("Failed to delete profile after RBUS_METHOD failures: %s\n", profile->name); - T2Info("%s --out\n", __FUNCTION__); - //return NULL; - goto reportThreadEnd; - } - T2Info("%s --out\n", __FUNCTION__); - //return NULL; - goto reportThreadEnd; - } - } - } - else if(profile->cachedReportList != NULL && Vector_Size(profile->cachedReportList) > 0) - { - T2Info("Trying to send %lu cached reports\n", (unsigned long )Vector_Size(profile->cachedReportList)); - if(strcmp(profile->protocol, "HTTP") == 0) - { - ret = sendCachedReportsOverHTTP(httpUrl, profile->cachedReportList); - } - else - { - ret = sendCachedReportsOverRBUSMethod(profile->t2RBUSDest->rbusMethodName, profile->t2RBUSDest->rbusMethodParamList, - profile->cachedReportList); - } - - if(ret == T2ERROR_SUCCESS) - { - removeProfileFromDisk(CACHED_MESSAGE_PATH, profile->name); - } - } - if(httpUrl) - { - free(httpUrl); - httpUrl = NULL; - } - } - else - { - T2Error("Unsupported report send protocol : %s\n", profile->protocol); - } - } - } - else - { - T2Error("Unsupported encoding format : %s\n", profile->encodingType); - } - clockReturn |= clock_gettime(CLOCK_MONOTONIC, &endTime); - if(clockReturn) - { - T2Warning("Failed to get time from clock_gettime()"); - } - else - { - getLapsedTime(&elapsedTime, &endTime, &startTime); - T2Info("Elapsed Time for : %s = %lu.%lu (Sec.NanoSec)\n", profile->name, (unsigned long )elapsedTime.tv_sec, elapsedTime.tv_nsec); - } - if(ret == T2ERROR_SUCCESS && jsonReport) - { - free(jsonReport); - jsonReport = NULL; - } - - pthread_mutex_lock(&profile->reuseThreadMutex); - pthread_mutex_lock(&profile->reportInProgressMutex); - profile->reportInProgress = false; - pthread_cond_signal(&profile->reportInProgressCond); - pthread_mutex_unlock(&profile->reportInProgressMutex); - pthread_mutex_unlock(&profile->reuseThreadMutex); - if(profile->triggerReportOnCondition) - { - T2Info(" Unlock trigger condition mutex and set report on condition to false \n"); - profile->triggerReportOnCondition = false ; - pthread_mutex_unlock(&profile->triggerCondMutex); - - if(profile->callBackOnReportGenerationComplete) - { - T2Debug("Calling callback function profile->callBackOnReportGenerationComplete \n"); - profile->callBackOnReportGenerationComplete(profile->name); - } - } - else - { - T2Debug(" profile->triggerReportOnCondition is not set \n"); - } -reportThreadEnd : - T2Info("%s while Loop -- END; wait for restart event\n", __FUNCTION__); - T2Info("%s --out\n", __FUNCTION__); - pthread_mutex_lock(&profile->reuseThreadMutex); - while(profile->enable && !profile->restartRequested) - { - pthread_cond_wait(&profile->reuseThread, &profile->reuseThreadMutex); - } - profile->restartRequested = false; - } - while(profile->enable); - pthread_mutex_unlock(&profile->reuseThreadMutex); - T2Info("%s --out Exiting collect and report Thread\n", __FUNCTION__); - pthread_mutex_lock(&profile->reuseThreadMutex); - pthread_mutex_lock(&profile->reportInProgressMutex); - profile->reportInProgress = false; - pthread_cond_signal(&profile->reportInProgressCond); - pthread_mutex_unlock(&profile->reportInProgressMutex); - pthread_mutex_unlock(&profile->reuseThreadMutex); - pthread_mutex_lock(&profile->reuseThreadMutex); - profile->threadExists = false; - pthread_mutex_unlock(&profile->reuseThreadMutex); - pthread_mutex_destroy(&profile->reuseThreadMutex); - pthread_cond_destroy(&profile->reuseThread); - return NULL; -} - -void NotifyTimeout(const char* profileName, bool isClearSeekMap) -{ - T2Debug("%s ++in\n", __FUNCTION__); - pthread_rwlock_rdlock(&profileListLock); - - Profile *profile = NULL; - if(T2ERROR_SUCCESS != getProfile(profileName, &profile)) - { - T2Error("Profile : %s not found\n", profileName); - pthread_rwlock_unlock(&profileListLock); - return ; - } - - pthread_rwlock_unlock(&profileListLock); - T2Info("%s: profile %s is in %s state\n", __FUNCTION__, profileName, profile->enable ? "Enabled" : "Disabled"); - pthread_mutex_lock(&profile->reportInProgressMutex); - if(profile->enable && !profile->reportInProgress) - { - profile->reportInProgress = true; - profile->bClearSeekMap = isClearSeekMap; - pthread_mutex_unlock(&profile->reportInProgressMutex); - - /* Read threadExists under reuseThreadMutex for proper synchronization. - * threadExists is written under reuseThreadMutex in CollectAndReport, - * so it must also be read under the same mutex to avoid a data race. - * Combine the read and the signal within the same lock to prevent a - * race between reading threadExists and signaling/creating the thread. */ - pthread_mutex_lock(&profile->reuseThreadMutex); - if (profile->threadExists) - { - T2Info("Signal Thread To restart\n"); - profile->restartRequested = true; - pthread_cond_signal(&profile->reuseThread); - pthread_mutex_unlock(&profile->reuseThreadMutex); - } - else - { - pthread_mutex_unlock(&profile->reuseThreadMutex); - pthread_create(&profile->reportThread, NULL, CollectAndReport, (void*)profile); - } - } - else - { - T2Warning("Either profile is disabled or report generation still in progress - ignoring the request\n"); - pthread_mutex_unlock(&profile->reportInProgressMutex); - } - T2Debug("%s --out\n", __FUNCTION__); -} - -T2ERROR Profile_storeMarkerEvent(const char *profileName, T2Event *eventInfo) -{ - T2Debug("%s ++in\n", __FUNCTION__); - - pthread_rwlock_rdlock(&profileListLock); - Profile *profile = NULL; - if(T2ERROR_SUCCESS != getProfile(profileName, &profile)) - { - T2Error("Profile : %s not found\n", profileName); - pthread_rwlock_unlock(&profileListLock); - return T2ERROR_FAILURE; - } - pthread_rwlock_unlock(&profileListLock); - if(!profile->enable) - { - T2Warning("Profile : %s is disabled, ignoring the event\n", profileName); - return T2ERROR_FAILURE; - } - size_t eventIndex = 0; - EventMarker *lookupEvent = NULL; - for(; eventIndex < Vector_Size(profile->eMarkerList); eventIndex++) - { - EventMarker *tempEventMarker = (EventMarker *)Vector_At(profile->eMarkerList, eventIndex); - if(!strcmp(tempEventMarker->markerName, eventInfo->name)) - { - lookupEvent = tempEventMarker; - break; - } - } - int arraySize = 0; - if(lookupEvent != NULL) - { - char buf[256] = {'\0'}; - char timebuf[256] = {'\0'}; - time_t timestamp = 0; - pthread_mutex_lock(&profile->eventMutex); - switch(lookupEvent->mType) - { - case MTYPE_COUNTER: - lookupEvent->u.count++; - T2Debug("Increment marker count to : %d\n", lookupEvent->u.count); - if(lookupEvent->reportTimestampParam == REPORTTIMESTAMP_UNIXEPOCH) - { - if(lookupEvent->timestamp) - { - free(lookupEvent->timestamp); - lookupEvent->timestamp = NULL; - } - - timestamp = time(NULL); - if(lookupEvent->markerName_CT == NULL) - { - if(lookupEvent->alias != NULL) - { - snprintf(buf, MAX_LEN, "%s_CT", lookupEvent->alias); - } - else - { - snprintf(buf, MAX_LEN, "%s_CT", lookupEvent->markerName); - } - lookupEvent->markerName_CT = strdup(buf); - } - snprintf(timebuf, MAX_LEN, "%ld", (long) timestamp); - lookupEvent->timestamp = strdup(timebuf); - T2Debug("Timestamp for %s is %s\n", lookupEvent->markerName_CT, lookupEvent->timestamp); - } - break; - - case MTYPE_ACCUMULATE: - T2Debug("Marker type is ACCUMULATE Event Value : %s\n", eventInfo->value); - arraySize = Vector_Size(lookupEvent->u.accumulatedValues); - T2Debug("Current array size : %d \n", arraySize); - if( arraySize < MAX_ACCUMULATE) - { - Vector_PushBack(lookupEvent->u.accumulatedValues, strdup(eventInfo->value)); - T2Debug("Sucessfully added value into vector New Size : %d\n", ++arraySize); - if(lookupEvent->reportTimestampParam == REPORTTIMESTAMP_UNIXEPOCH) - { - timestamp = time(NULL); - if(lookupEvent->markerName_CT == NULL) - { - if(lookupEvent->alias != NULL) - { - snprintf(buf, MAX_LEN, "%s_CT", lookupEvent->alias); - } - else - { - snprintf(buf, MAX_LEN, "%s_CT", lookupEvent->markerName); - } - lookupEvent->markerName_CT = strdup(buf); - } - snprintf(timebuf, MAX_LEN, "%ld", (long) timestamp); - T2Debug("Timestamp for %s is %ld\n", lookupEvent->markerName_CT, (long) timestamp); - Vector_PushBack(lookupEvent->accumulatedTimestamp, strdup(timebuf)); - T2Debug("Vector_PushBack for accumulatedTimestamp is done\n"); - } - } - else if ( arraySize == MAX_ACCUMULATE ) - { - T2Warning("Max size of the array has been reached appending warning message : %s\n", MAX_ACCUMULATE_MSG); - Vector_PushBack(lookupEvent->u.accumulatedValues, strdup(MAX_ACCUMULATE_MSG)); - T2Debug("Sucessfully added warning message into vector New Size : %d\n", ++arraySize); - } - else - { - T2Warning("Max size of the array has been reached Ignore New Value\n"); - } - break; - - case MTYPE_ABSOLUTE: - default: - if(lookupEvent->u.markerValue) - { - free(lookupEvent->u.markerValue); - lookupEvent->u.markerValue = NULL; - } - - lookupEvent->u.markerValue = strdup(eventInfo->value); - T2Debug("New marker value saved : %s\n", lookupEvent->u.markerValue); - if(lookupEvent->reportTimestampParam == REPORTTIMESTAMP_UNIXEPOCH) - { - if(lookupEvent->timestamp) - { - free(lookupEvent->timestamp); - lookupEvent->timestamp = NULL; - } - - timestamp = time(NULL); - if(lookupEvent->markerName_CT == NULL) - { - if(lookupEvent->alias != NULL) - { - snprintf(buf, MAX_LEN, "%s_CT", lookupEvent->alias); - } - else - { - snprintf(buf, MAX_LEN, "%s_CT", lookupEvent->markerName); - } - lookupEvent->markerName_CT = strdup(buf); - } - snprintf(timebuf, MAX_LEN, "%ld", (long)timestamp); - lookupEvent->timestamp = strdup(timebuf); - T2Debug("Timestamp for %s is %s\n", lookupEvent->markerName_CT, lookupEvent->timestamp); - } - break; - } - pthread_mutex_unlock(&profile->eventMutex); - } - else - { - T2Error("Event name : %s value : %s\n", eventInfo->name, eventInfo->value); - T2Error("Event doens't match any marker information, shouldn't come here\n"); - return T2ERROR_FAILURE; - } - - T2Debug("%s --out\n", __FUNCTION__); - return T2ERROR_SUCCESS; -} - -T2ERROR addProfile(Profile *profile) -{ - T2Debug("%s ++in\n", __FUNCTION__); - if(!initialized) - { - T2Error("profile list is not initialized yet, ignoring\n"); - return T2ERROR_FAILURE; - } - pthread_rwlock_wrlock(&profileListLock); - Vector_PushBack(profileList, profile); - - pthread_rwlock_unlock(&profileListLock); - T2Debug("%s --out\n", __FUNCTION__); - return T2ERROR_SUCCESS; -} - -T2ERROR enableProfile(const char *profileName) -{ - T2Debug("%s ++in \n", __FUNCTION__); - if(!initialized) - { - T2Error("profile list is not initialized yet, ignoring\n"); - return T2ERROR_FAILURE; - } - pthread_rwlock_rdlock(&profileListLock); - Profile *profile = NULL; - if(T2ERROR_SUCCESS != getProfile(profileName, &profile)) - { - T2Error("Profile : %s not found\n", profileName); - pthread_rwlock_unlock(&profileListLock); - return T2ERROR_FAILURE; - } - if(profile->enable) - { - T2Info("Profile : %s is already enabled - ignoring duplicate request\n", profileName); - pthread_rwlock_unlock(&profileListLock); - return T2ERROR_SUCCESS; - } - else - { - profile->enable = true; - if(pthread_mutex_init(&profile->triggerCondMutex, NULL) != 0) - { - T2Error(" %s Mutex init has failed\n", __FUNCTION__); - pthread_rwlock_unlock(&profileListLock); - return T2ERROR_FAILURE; - } - if(pthread_mutex_init(&profile->reportInProgressMutex, NULL) != 0) - { - T2Error(" %s Mutex init has failed\n", __FUNCTION__); - pthread_rwlock_unlock(&profileListLock); - return T2ERROR_FAILURE; - } - if(pthread_cond_init(&profile->reportInProgressCond, NULL) != 0) - { - T2Error(" %s Cond init has failed\n", __FUNCTION__); - pthread_rwlock_unlock(&profileListLock); - return T2ERROR_FAILURE; - } - - size_t emIndex = 0; - EventMarker *eMarker = NULL; - for(; emIndex < Vector_Size(profile->eMarkerList); emIndex++) - { - eMarker = (EventMarker *)Vector_At(profile->eMarkerList, emIndex); - addT2EventMarker(eMarker->markerName, eMarker->compName, profile->name, eMarker->skipFreq); - } - if(registerProfileWithScheduler(profile->name, profile->reportingInterval, profile->activationTimeoutPeriod, profile->deleteonTimeout, true, profile->reportOnUpdate, profile->firstReportingInterval, profile->timeRef) != T2ERROR_SUCCESS) - { - profile->enable = false; - T2Error("Unable to register profile : %s with Scheduler\n", profileName); - pthread_rwlock_unlock(&profileListLock); - return T2ERROR_FAILURE; - } - T2ER_StartDispatchThread(); - - T2Info("Successfully enabled profile : %s\n", profileName); - } - T2Debug("%s --out\n", __FUNCTION__); - pthread_rwlock_unlock(&profileListLock); - return T2ERROR_SUCCESS; -} - - -void updateMarkerComponentMap() -{ - T2Debug("%s ++in\n", __FUNCTION__); - - size_t profileIndex = 0; - Profile *tempProfile = NULL; - - pthread_rwlock_rdlock(&profileListLock); - for(; profileIndex < Vector_Size(profileList); profileIndex++) - { - tempProfile = (Profile *)Vector_At(profileList, profileIndex); - if(tempProfile->enable) - { - T2Debug("Updating component map for profile %s \n", tempProfile->name); - size_t emIndex = 0; - EventMarker *eMarker = NULL; - for(; emIndex < Vector_Size(tempProfile->eMarkerList); emIndex++) - { - eMarker = (EventMarker *)Vector_At(tempProfile->eMarkerList, emIndex); - addT2EventMarker(eMarker->markerName, eMarker->compName, tempProfile->name, eMarker->skipFreq); - } - } - } - pthread_rwlock_unlock(&profileListLock); - T2Debug("%s --out\n", __FUNCTION__); -} - -T2ERROR disableProfile(const char *profileName, bool *isDeleteRequired) -{ - T2Debug("%s ++in \n", __FUNCTION__); - - if(!initialized) - { - T2Error("profile list is not initialized yet, ignoring\n"); - return T2ERROR_FAILURE; - } - - pthread_rwlock_rdlock(&profileListLock); - Profile *profile = NULL; - if(T2ERROR_SUCCESS != getProfile(profileName, &profile)) - { - T2Error("Profile : %s not found\n", profileName); - pthread_rwlock_unlock(&profileListLock); - return T2ERROR_FAILURE; - } - - if (profile->generateNow) - { - *isDeleteRequired = true; - } - else - { - profile->enable = false; - } -#ifdef PERSIST_LOG_MON_REF - removeProfileFromDisk(SEEKFOLDER, profile->name); -#endif - profile->isSchedulerstarted = false; - pthread_rwlock_unlock(&profileListLock); - T2Debug("%s --out\n", __FUNCTION__); - - return T2ERROR_SUCCESS; -} - -T2ERROR deleteAllProfiles(bool delFromDisk) -{ - T2Debug("%s ++in\n", __FUNCTION__); - - int count = 0; - int profileIndex = 0; - Profile *tempProfile = NULL; - - pthread_rwlock_wrlock(&profileListLock); - if(profileList == NULL) - { - T2Error("profile list is not initialized yet or profileList is empty, ignoring\n"); - pthread_rwlock_unlock(&profileListLock); - return T2ERROR_FAILURE; - } - - count = Vector_Size(profileList); - pthread_rwlock_unlock(&profileListLock); - - for(; profileIndex < count; profileIndex++) - { - pthread_rwlock_rdlock(&profileListLock); - tempProfile = (Profile *)Vector_At(profileList, profileIndex); - tempProfile->enable = false; - tempProfile->isSchedulerstarted = false; - pthread_rwlock_unlock(&profileListLock); - - if(T2ERROR_SUCCESS != unregisterProfileFromScheduler(tempProfile->name)) - { - T2Error("Profile : %s failed to unregister from scheduler\n", tempProfile->name); - } - - /* Read threadExists under reuseThreadMutex: threadExists is written under - * reuseThreadMutex in CollectAndReport, so reads must use the same lock. - * The thread sets threadExists = false and then destroys reuseThreadMutex - * before returning, so reuseThreadMutex must not be accessed after join. */ - pthread_mutex_lock(&tempProfile->reuseThreadMutex); - bool threadStillExists = tempProfile->threadExists; - if (threadStillExists) - { - tempProfile->restartRequested = true; - pthread_cond_signal(&tempProfile->reuseThread); - } - pthread_mutex_unlock(&tempProfile->reuseThreadMutex); - - if (threadStillExists) - { - pthread_join(tempProfile->reportThread, NULL); - /* Do not access reuseThreadMutex after join: the thread destroys it - * after setting threadExists = false (see CollectAndReport cleanup). */ - } - - /* Re-acquire profileListLock for profile cleanup */ - pthread_rwlock_rdlock(&profileListLock); - if(tempProfile->grepSeekProfile) - { - freeGrepSeekProfile(tempProfile->grepSeekProfile); - } - pthread_rwlock_unlock(&profileListLock); - if(delFromDisk == true) - { - removeProfileFromDisk(REPORTPROFILES_PERSISTENCE_PATH, tempProfile->name); -#ifdef PERSIST_LOG_MON_REF - removeProfileFromDisk(SEEKFOLDER, tempProfile->name); -#endif - } - } - if(delFromDisk == true) - { - removeProfileFromDisk(REPORTPROFILES_PERSISTENCE_PATH, MSGPACK_REPORTPROFILES_PERSISTENT_FILE); - } - - pthread_rwlock_wrlock(&profileListLock); - T2Debug("Deleting all profiles from the profileList\n"); - Vector_Destroy(profileList, freeProfile); - profileList = NULL; - Vector_Create(&profileList); - pthread_rwlock_unlock(&profileListLock); - - T2Debug("%s --out\n", __FUNCTION__); - - return T2ERROR_SUCCESS; -} - -bool isProfileEnabled(const char *profileName) -{ - bool is_profile_enable = false; - Profile *get_profile = NULL; - pthread_rwlock_rdlock(&profileListLock); - if(T2ERROR_SUCCESS != getProfile(profileName, &get_profile)) - { - T2Error("Profile : %s not found\n", profileName); - T2Debug("%s --out\n", __FUNCTION__); - pthread_rwlock_unlock(&profileListLock); - return false; - } - is_profile_enable = get_profile->enable; - T2Debug("is_profile_enable = %d \n", is_profile_enable); - pthread_rwlock_unlock(&profileListLock); - return is_profile_enable; -} - - -T2ERROR deleteProfile(const char *profileName) -{ - T2Debug("%s ++in\n", __FUNCTION__); - if(!initialized) - { - T2Error("profile list is not initialized yet, ignoring\n"); - return T2ERROR_FAILURE; - } - - Profile *profile = NULL; - pthread_rwlock_rdlock(&profileListLock); - if(T2ERROR_SUCCESS != getProfile(profileName, &profile)) - { - T2Error("Profile : %s not found\n", profileName); - pthread_rwlock_unlock(&profileListLock); - return T2ERROR_FAILURE; - } - - if(profile->enable) - { - profile->enable = false; - } - if(profile->isSchedulerstarted) - { - profile->isSchedulerstarted = false; - } - pthread_rwlock_unlock(&profileListLock); - if(T2ERROR_SUCCESS != unregisterProfileFromScheduler(profileName)) - { - T2Info("Profile : %s already removed from scheduler\n", profileName); - } - - T2Info("Waiting for CollectAndReport to be complete : %s\n", profileName); - pthread_rwlock_rdlock(&profileListLock); - - // Wait for any in-progress report to finish under reportInProgressMutex. - // threadExists must NOT be read here — it is written under reuseThreadMutex - // in CollectAndReport, so mixing the two mutexes causes a data race (Coverity - // LOCK_EVASION). Read threadExists separately under reuseThreadMutex below. - pthread_mutex_lock(&profile->reportInProgressMutex); - while (profile->reportInProgress) - { - pthread_cond_wait(&profile->reportInProgressCond, &profile->reportInProgressMutex); - } - pthread_mutex_unlock(&profile->reportInProgressMutex); - - /* Read threadExists under reuseThreadMutex: it is written under the same mutex - * in CollectAndReport. The thread sets threadExists = false and then destroys - * reuseThreadMutex before returning, so reuseThreadMutex must not be used after - * pthread_join returns. */ - pthread_mutex_lock(&profile->reuseThreadMutex); - bool threadStillExists = profile->threadExists; - pthread_mutex_unlock(&profile->reuseThreadMutex); - - /* Release profileListLock before pthread_join to avoid deadlock. - * pthread_join can block indefinitely if the CollectAndReport thread - * is stuck (e.g., waiting on rbusMethodMutex). Holding profileListLock during - * pthread_join prevents other threads (timeout callbacks, other profile - * operations) from making progress, creating a deadlock. - */ - pthread_rwlock_unlock(&profileListLock); - - if (threadStillExists) - { - pthread_mutex_lock(&profile->reuseThreadMutex); - profile->restartRequested = true; - pthread_cond_signal(&profile->reuseThread); - pthread_mutex_unlock(&profile->reuseThreadMutex); - pthread_join(profile->reportThread, NULL); - /* Do not access reuseThreadMutex after join: the thread destroys it - * after setting threadExists = false (see CollectAndReport cleanup). */ - } - - /* Re-acquire profileListLock (wrlock) for profile cleanup operations */ - pthread_rwlock_wrlock(&profileListLock); - - if(Vector_Size(profile->triggerConditionList) > 0) - { - rbusT2ConsumerUnReg(profile->triggerConditionList); - } - - if(profile->grepSeekProfile) - { - freeGrepSeekProfile(profile->grepSeekProfile); - } - - pthread_mutex_destroy(&profile->reportInProgressMutex); - pthread_cond_destroy(&profile->reportInProgressCond); - - T2Info("removing profile : %s from profile list\n", profile->name); -#ifdef PERSIST_LOG_MON_REF - removeProfileFromDisk(SEEKFOLDER, profile->name); -#endif - Vector_RemoveItem(profileList, profile, freeProfile); - - pthread_rwlock_unlock(&profileListLock); - T2Debug("%s --out\n", __FUNCTION__); - return T2ERROR_SUCCESS; -} - -void sendLogUploadInterruptToScheduler() -{ - size_t profileIndex = 0; - Profile *tempProfile = NULL; - T2Debug("%s ++in\n", __FUNCTION__); - - pthread_rwlock_rdlock(&profileListLock); - for(; profileIndex < Vector_Size(profileList); profileIndex++) - { - tempProfile = (Profile *)Vector_At(profileList, profileIndex); - if (Vector_Size(tempProfile->gMarkerList) > 0) - { - SendInterruptToTimeoutThread(tempProfile->name); - } - } - pthread_rwlock_unlock(&profileListLock); - T2Debug("%s --out\n", __FUNCTION__); -} - -static void loadReportProfilesFromDisk(bool checkPreviousSeek) -{ - (void)checkPreviousSeek; - fetchLocalConfigs(SHORTLIVED_PROFILES_PATH, NULL); //API used for creating /tmp/t2reportprofiles dir -#if defined(FEATURE_SUPPORT_WEBCONFIG) - T2Info("loadReportProfilesFromDisk \n"); - char filePath[REPORTPROFILES_FILE_PATH_SIZE] = {'\0'}; - snprintf(filePath, sizeof(filePath), "%s%s", REPORTPROFILES_PERSISTENCE_PATH, MSGPACK_REPORTPROFILES_PERSISTENT_FILE); - /* CID: 157386 Time of check time of use (TOCTOU) */ - FILE *fp; - fp = fopen (filePath, "rb"); - if(fp != NULL) - { - T2Info("Msgpack: loadReportProfilesFromDisk \n"); - struct __msgpack__ msgpack; - fseek(fp, 0L, SEEK_END); - msgpack.msgpack_blob_size = ftell(fp); - if(msgpack.msgpack_blob_size < 0) - { - T2Error("Unable to detect the file pointer position for file %s\n", filePath); - fclose(fp); - return; - } - msgpack.msgpack_blob = malloc(sizeof(char) * msgpack.msgpack_blob_size); - if (NULL == msgpack.msgpack_blob) - { - T2Error("Unable to allocate %d bytes of memory at Line %d on %s \n", - msgpack.msgpack_blob_size, __LINE__, __FILE__); - fclose (fp); - return; - } - fseek(fp, 0L, SEEK_SET); - if(fread(msgpack.msgpack_blob, sizeof(char), msgpack.msgpack_blob_size, fp) < (size_t) msgpack.msgpack_blob_size) - { - T2Error("fread is returning fewer bytes than expected from the file %s\n", filePath); - free(msgpack.msgpack_blob); - fclose(fp); - return; - } - fclose (fp); - __ReportProfiles_ProcessReportProfilesMsgPackBlob((void *)&msgpack, checkPreviousSeek); - free(msgpack.msgpack_blob); - clearPersistenceFolder(CACHED_MESSAGE_PATH); - return; - } - T2Info("JSON: loadReportProfilesFromDisk \n"); -#endif -#if defined(PRIVACYMODES_CONTROL) - char* paramValue = NULL; - getPrivacyMode(¶mValue); - if(strcmp(paramValue, "DO_NOT_SHARE") == 0) - { - T2Warning("PrivacyModes is DO_NOT_SHARE. Reportprofiles is not supported\n"); - free(paramValue); - paramValue = NULL; - return; - } - free(paramValue); - paramValue = NULL; -#endif - - size_t configIndex = 0; - Vector *configList = NULL; - Config *config = NULL; - T2Debug("%s ++in\n", __FUNCTION__); - - Vector_Create(&configList); - fetchLocalConfigs(REPORTPROFILES_PERSISTENCE_PATH, configList); - - for(; configIndex < Vector_Size(configList); configIndex++) - { - config = Vector_At(configList, configIndex); - Profile *profile = 0; - T2Debug("Processing config with name : %s\n", config->name); - T2Debug("Config Size = %lu\n", (unsigned long)strlen(config->configData)); - - if(T2ERROR_SUCCESS == processConfiguration(&config->configData, config->name, NULL, &profile)) - { - if(T2ERROR_SUCCESS == addProfile(profile)) - { -#ifdef PERSIST_LOG_MON_REF - if(checkPreviousSeek && profile->generateNow == false && profile->triggerConditionList == NULL && profile->grepSeekProfile && loadSavedSeekConfig(profile->name, profile->grepSeekProfile) == T2ERROR_SUCCESS && firstBootStatus() ) - { - profile->checkPreviousSeek = true; - } - else - { - profile->checkPreviousSeek = false; - } -#else - profile->checkPreviousSeek = false; -#endif - T2Info("Successfully created/added new profile : %s\n", profile->name); - if(T2ERROR_SUCCESS != enableProfile(profile->name)) - { - T2Error("Failed to enable profile name : %s\n", profile->name); - } - else - { - -#ifdef PERSIST_LOG_MON_REF - if(profile->checkPreviousSeek) - { - T2Info("Previous Seek is enabled so generate the report for %s\n", profile->name); - // Trigger the report generation for the profile if previous seek is valid - NotifyTimeout(profile->name, true); - } -#endif - // Load the cached messages from previous boot, if any - populateCachedReportList(profile->name, profile->cachedReportList); - } - } - else - { - T2Error("Unable to create and add new profile for name : %s\n", config->name); - if (profile != NULL) - { - freeProfile(profile); - profile = NULL; - } - } - } - } - T2Info("Completed processing %lu profiles on the disk,trying to fetch new/updated profiles\n", (unsigned long)Vector_Size(configList)); - T2totalmem_calculate(); - Vector_Destroy(configList, freeReportProfileConfig); - clearPersistenceFolder(CACHED_MESSAGE_PATH); - - T2Debug("%s --out\n", __FUNCTION__); -} - -T2ERROR initProfileList(bool checkPreviousSeek) -{ - T2Debug("%s ++in\n", __FUNCTION__); - if(initialized) - { - T2Info("profile list is already initialized\n"); - return T2ERROR_SUCCESS; - } - initialized = true; - if(pthread_rwlock_init(&profileListLock, NULL) != 0) - { - T2Error("%s rwlock init has failed\n", __FUNCTION__); - return T2ERROR_FAILURE; - } - if(pthread_mutex_init(&reportLock, NULL) != 0 ) - { - T2Error("%s mutex init has failed\n", __FUNCTION__); - pthread_rwlock_destroy(&profileListLock); - initialized = false; - return T2ERROR_FAILURE; - } - - pthread_rwlock_wrlock(&profileListLock); - Vector_Create(&profileList); - pthread_rwlock_unlock(&profileListLock); - - registerConditionalReportCallBack(&triggerReportOnCondtion); - - loadReportProfilesFromDisk(checkPreviousSeek); - - T2Debug("%s --out\n", __FUNCTION__); - return T2ERROR_SUCCESS; -} - -int getProfileCount() -{ - int count = 0; - T2Debug("%s ++in\n", __FUNCTION__); - if(!initialized) - { - T2Info("profile list isn't initialized\n"); - return count; - } - pthread_rwlock_rdlock(&profileListLock); - count = Vector_Size(profileList); - pthread_rwlock_unlock(&profileListLock); - - T2Debug("%s --out\n", __FUNCTION__); - return count; -} - -hash_map_t *getProfileHashMap() -{ - size_t profileIndex = 0; - hash_map_t *profileHashMap = NULL; - Profile *tempProfile = NULL; - T2Debug("%s ++in\n", __FUNCTION__); - - pthread_rwlock_rdlock(&profileListLock); - profileHashMap = hash_map_create(); - for(; profileIndex < Vector_Size(profileList); profileIndex++) - { - tempProfile = (Profile *)Vector_At(profileList, profileIndex); - char *profileName = strdup(tempProfile->name); - char *profileHash = strdup(tempProfile->hash); - hash_map_put(profileHashMap, profileName, profileHash, free); - } - pthread_rwlock_unlock(&profileListLock); - - T2Debug("%s --out\n", __FUNCTION__); - return profileHashMap; -} - -T2ERROR uninitProfileList() -{ - T2Debug("%s ++in\n", __FUNCTION__); - - if(!initialized) - { - T2Info("profile list is not initialized yet, ignoring\n"); - return T2ERROR_SUCCESS; - } - - initialized = false; - deleteAllProfiles(false); // avoid removing multiProfiles from Disc - - if(!pthread_mutex_trylock(&triggerConditionQueMutex)) - { - if(triggerConditionQueue) - { - t2_queue_destroy(triggerConditionQueue, free); - } - - pthread_mutex_unlock(&triggerConditionQueMutex); - } - - pthread_mutex_destroy(&reportLock); - pthread_rwlock_destroy(&profileListLock); - - T2Debug("%s --out\n", __FUNCTION__); - return T2ERROR_SUCCESS; -} - -T2ERROR registerTriggerConditionConsumer() -{ - - T2Debug("%s ++in\n", __FUNCTION__); -#define MAX_RETRY_COUNT 3 - size_t profileIndex = 0; - int retry_count = 0; - int retry = 0; - int timer = 16; - int ret = T2ERROR_SUCCESS; - Profile *tempProfile = NULL; - - while(retry_count <= MAX_RETRY_COUNT) - { - pthread_rwlock_rdlock(&profileListLock); - profileIndex = 0; - for(; profileIndex < Vector_Size(profileList); profileIndex++) - { - tempProfile = (Profile *)Vector_At(profileList, profileIndex); - if(tempProfile->triggerConditionList) - { - ret = rbusT2ConsumerReg(tempProfile->triggerConditionList); - T2Debug("rbusT2ConsumerReg return = %d\n", ret); - if(ret != T2ERROR_SUCCESS) - { - retry = 1; - } - } - - } - pthread_rwlock_unlock(&profileListLock); - if(retry == 1) - { - if(retry_count >= MAX_RETRY_COUNT) - { - break; - } - T2Debug("Retry Consumer Registration in %d sec\n", timer); - retry_count++; - retry = 0; - sleep(timer); - timer = timer / 2; - } - else - { - break; - } - } - T2Debug("%s --out\n", __FUNCTION__); - return ret; -} - -void NotifySchedulerstart(char* profileName, bool isschedulerstarted) -{ - size_t profileIndex = 0; - Profile *tempProfile = NULL; - pthread_rwlock_rdlock(&profileListLock); - T2Debug("profileListLock is rdlocked %s\n", __FUNCTION__); - for(; profileIndex < Vector_Size(profileList); profileIndex++) - { - tempProfile = (Profile *)Vector_At(profileList, profileIndex); - if(tempProfile != NULL) - { - if(strncmp(tempProfile->name, profileName, strlen(profileName) + 1) == 0) - { - tempProfile->isSchedulerstarted = isschedulerstarted; - } - } - } - pthread_rwlock_unlock(&profileListLock); - T2Debug("profileListLock is unlocked %s\n", __FUNCTION__); - return; -} - -T2ERROR appendTriggerCondition (Profile *tempProfile, const char *referenceName, const char *referenceValue) -{ - T2Debug("%s ++in\n", __FUNCTION__); - - T2ERROR status = T2ERROR_SUCCESS ; - - // triggerCondMutex is purposefully left unlocked from this function. - // It gets released from CollectAndReport thread once trigger condition based report is sent out. - // Reports from multiple trigger condition has to be sent mutually exclusively as separate reports. - if(!pthread_mutex_trylock(&tempProfile->triggerCondMutex)) - { - T2Debug("%s : Lock acquisition succeeded for tempProfile->triggerCondMutex\n ", __FUNCTION__); - cJSON *temparrayItem = cJSON_CreateObject(); - cJSON_AddStringToObject(temparrayItem, "reference", referenceName); - cJSON_AddStringToObject(temparrayItem, "value", referenceValue); - cJSON *temparrayItem1 = cJSON_CreateObject(); - - cJSON_AddItemToObject(temparrayItem1, "TriggerConditionResult", temparrayItem); - tempProfile->jsonReportObj = temparrayItem1; - //pthread_mutex_unlock(&tempProfile->triggerCondMutex); - - } - else - { - T2Warning("%s : Failed to get a lock on tempProfile->triggerCondMutex for condition %s \n ", __FUNCTION__, referenceName); - status = T2ERROR_FAILURE; - // Push this trigger condition to a que. - // Implement a callback function to trigger report generation for referenceName & value - - if(!pthread_mutex_trylock(&triggerConditionQueMutex)) - { - T2Debug("%s : Lock on triggerConditionQueMutex\n", __FUNCTION__); - if(NULL == triggerConditionQueue) - { - triggerConditionQueue = t2_queue_create(); - if(!triggerConditionQueue) - { - T2Error("Failed to create triggerConditionQueue, not proceeding further\n"); - T2Debug("%s : Unlock on triggerConditionQueMutex\n", __FUNCTION__); - pthread_mutex_unlock(&triggerConditionQueMutex); - T2Debug("%s --out\n", __FUNCTION__); - return status ; - } - T2Debug("%s : Que for storing the trigger conditions is created \n", __FUNCTION__); - } - triggerConditionObj *triggerCond = (triggerConditionObj*) malloc(sizeof(triggerConditionObj)); - if(triggerCond) - { - if(NULL != referenceName && NULL != referenceValue) - { - T2Info("%s : Push referenceName = %s & referenceValue = %s to que \n ", __FUNCTION__, referenceName, referenceValue); - memset(triggerCond, 0, sizeof(triggerConditionObj)); - strncpy(triggerCond->referenceName, referenceName, (MAX_LEN - 1)); - strncpy(triggerCond->referenceValue, referenceValue, (MAX_LEN - 1)); - t2_queue_push(triggerConditionQueue, (void*) triggerCond); - // Ownership of triggerCond is transferred to triggerConditionQueue and will be freed after being popped. - } - else - { - T2Warning("%s : referenceName or referenceValue is published as null, ignoring trigger condition \n ", __FUNCTION__); - } - - } - else - { - T2Error("Failed to allocate memory for triggerConditionObj\n"); - } - - T2Debug("%s : Unlock on triggerConditionQueMutex\n", __FUNCTION__); - pthread_mutex_unlock(&triggerConditionQueMutex); - - /* ref RDKB-55438 Commenting following code as this is causing crash, we can't free triggerCond here as this - has been added to the queue, this is freed in the reportGenerationCompleteReceiver function after queue pop - - if(triggerCond != NULL) { - free(triggerCond);//CID 335291: Resource leak (RESOURCE_LEAK) - } - */ - - } - else - { - T2Warning("%s : Failed to get a lock on triggerConditionQueMutex for condition %s \n ", __FUNCTION__, referenceName); - - } - } - - T2Debug("%s --out\n", __FUNCTION__); - return status; -} - -void reportGenerationCompleteReceiver(char *profileName) -{ - - T2Debug("%s ++in\n", __FUNCTION__); - T2Info("%s called with argument %s\n", __FUNCTION__, profileName); - - if(!pthread_mutex_lock(&triggerConditionQueMutex)) - { - if(NULL != triggerConditionQueue) - { - T2Info("%s : %d report generating triggers pending in que \n ", __FUNCTION__, t2_queue_count(triggerConditionQueue)); - if(t2_queue_count(triggerConditionQueue) > 0) - { - triggerConditionObj *triggerCond = (triggerConditionObj*) t2_queue_pop(triggerConditionQueue); - if(triggerCond) - { - // Que has to be unlocked before generating a trigger condition - pthread_mutex_unlock(&triggerConditionQueMutex); - triggerReportOnCondtion(triggerCond->referenceName, triggerCond->referenceValue); - free(triggerCond); - triggerCond = NULL; - } - else - { - T2Debug("%s : Trigger condition is null \n", __FUNCTION__); - pthread_mutex_unlock(&triggerConditionQueMutex); - } - } - else - { - T2Debug("%s : Unlock on triggerConditionQueMutex\n", __FUNCTION__); - pthread_mutex_unlock(&triggerConditionQueMutex); - T2Debug("No more report on condition events present in que \n"); - } - } - else - { - pthread_mutex_unlock(&triggerConditionQueMutex); - } - } - else - { - T2Error("Failed to get lock on triggerConditionQueMutex \n"); - } - - T2Debug("%s --out\n", __FUNCTION__); -} - -T2ERROR triggerReportOnCondtion(const char *referenceName, const char *referenceValue) -{ - T2Debug("%s ++in\n", __FUNCTION__); - - T2Debug("referenceName = %s referenceValue = %s \n", referenceName, referenceValue); - - size_t j, profileIndex = 0; - Profile *tempProfile = NULL; - - pthread_rwlock_rdlock(&profileListLock); - for(; profileIndex < Vector_Size(profileList); profileIndex++) - { - tempProfile = (Profile *)Vector_At(profileList, profileIndex); - if(tempProfile->triggerConditionList && (tempProfile->triggerConditionList->count > 0)) - { - for( j = 0; j < tempProfile->triggerConditionList->count; j++ ) - { - TriggerCondition *triggerCondition = ((TriggerCondition *) Vector_At(tempProfile->triggerConditionList, j)); - if(strcmp(triggerCondition->reference, referenceName) == 0) - { - if(triggerCondition->report) - { - if ( T2ERROR_SUCCESS == appendTriggerCondition(tempProfile, referenceName, referenceValue)) - { - tempProfile->triggerReportOnCondition = true; - tempProfile->minThresholdDuration = triggerCondition->minThresholdDuration; - T2Debug("%s : Assign callback function as reportGenerationCompleteReceiver \n", __FUNCTION__); - tempProfile->callBackOnReportGenerationComplete = reportGenerationCompleteReceiver; - - char *tempProfilename = strdup(tempProfile->name); //RDKB-42640 - - // profileListLock should be unlocked before sending interrupt for report generation - T2Debug("%s : Release lock on &profileListLock\n ", __FUNCTION__); - pthread_rwlock_unlock(&profileListLock); - T2Info("Triggering report on condition for %s with %s operator, %d threshold\n", triggerCondition->reference, - triggerCondition->oprator, triggerCondition->threshold); - if(tempProfile->isSchedulerstarted) - { - SendInterruptToTimeoutThread(tempProfilename); - // triggerCondMutex will be unlocked by CollectAndReport after report generation - } - else - { - T2Info("For Profile %s scheduler is not enabled yet so triggering the condition is ignored now\n", tempProfilename); - tempProfile->triggerReportOnCondition = false; - pthread_mutex_unlock(&tempProfile->triggerCondMutex); - - } - free(tempProfilename); //RDKB-42640 - return T2ERROR_SUCCESS ; - } - else - { - T2Info("Report generation will take place by popping up from the que by callback function \n"); - T2Debug("%s : Release lock on &profileListLock\n ", __FUNCTION__); - pthread_rwlock_unlock(&profileListLock); - return T2ERROR_SUCCESS; - } - } - } - } - } - } - pthread_rwlock_unlock(&profileListLock); - T2Debug("%s --out\n", __FUNCTION__); - return T2ERROR_SUCCESS; -} - -unsigned int getMinThresholdDuration(char *profileName) -{ - unsigned int minThresholdDuration = 0; - Profile *get_profile = NULL; - T2Debug("%s --in\n", __FUNCTION__); - pthread_rwlock_rdlock(&profileListLock); - if(T2ERROR_SUCCESS != getProfile(profileName, &get_profile)) - { - T2Error("Profile : %s not found\n", profileName); - T2Debug("%s --out\n", __FUNCTION__); - pthread_rwlock_unlock(&profileListLock); - return 0; - } - minThresholdDuration = get_profile->minThresholdDuration; - get_profile->minThresholdDuration = 0; // reinit the value - T2Debug("minThresholdDuration = %u \n", minThresholdDuration); - pthread_rwlock_unlock(&profileListLock); - T2Debug("%s --out\n", __FUNCTION__); - return minThresholdDuration; -} - + JSONFormat reportFormat; + TimeStampFormat tsFormat; +} JSONEncoding; +/** + * Lock Hierarchy (acquire in ascending order to prevent deadlocks): + * L0: profileListLock (module-level rwlock - protects profileList) + * L1: reuseThreadMutex (per-profile - protects thread lifecycle) + * L2: reportInProgressMutex (per-profile - protects reportInProgress flag) + * L3: triggerCondMutex / eventMutex / reportMutex (per-profile - leaf locks) + * + * Rules: + * - Always acquire L0 before L1, L1 before L2, etc. + * - Never hold a higher-numbered lock when acquiring a lower-numbered lock. + * - profileListLock uses rdlock for lookups/iterations, wrlock for add/remove. + * - Release profileListLock before long operations (pthread_join, HTTP send). + */ +typedef struct _Profile +{ + bool enable; + bool isSchedulerstarted; + bool isUpdated; + bool reportInProgress; + pthread_cond_t reportInProgressCond; + pthread_mutex_t reportInProgressMutex; + bool generateNow; + bool deleteonTimeout; + bool bClearSeekMap; + bool checkPreviousSeek; // To support Previous_Logs report post reboot + bool saveSeekConfig; // To save the Seek config to persistant storage + bool triggerReportOnCondition; + bool trim; + void (*callBackOnReportGenerationComplete)(char*); + char* hash; + char* name; + char* protocol; + char* encodingType; + char* Description; + char* version; + char* RootName; + char* timeRef; + JSONEncoding *jsonEncoding; + bool reportOnUpdate; + unsigned int firstReportingInterval; + unsigned int SendErr; + unsigned int reportingInterval; + unsigned int activationTimeoutPeriod; + unsigned int maxUploadLatency; + unsigned int paramNumOfEntries; + unsigned int minThresholdDuration; + Vector *paramList; + Vector *staticParamList; + T2HTTP *t2HTTPDest; + T2RBUS *t2RBUSDest; + Vector *eMarkerList; + Vector *gMarkerList; + Vector *topMarkerList; + Vector *cachedReportList; + cJSON *jsonReportObj; + pthread_t reportThread; + pthread_mutex_t triggerCondMutex; + pthread_mutex_t eventMutex; + pthread_mutex_t reportMutex; + pthread_cond_t reportcond; + struct timespec currentTime; + struct timespec maxlatencyTime; + Vector *triggerConditionList; + pthread_cond_t reuseThread; + pthread_mutex_t reuseThreadMutex; + bool restartRequested; + bool threadExists; + GrepSeekProfile *grepSeekProfile; // To store GrepConfig +} Profile; + +T2ERROR initProfileList(bool checkPreviousSeek); + +T2ERROR uninitProfileList(); + +T2ERROR addProfile(Profile *profile); + +int getProfileCount(); + +T2ERROR profileWithNameExists(const char *profileName, bool *bProfileExists); + +T2ERROR Profile_storeMarkerEvent(const char *profileName, T2Event *eventInfo); + +T2ERROR enableProfile(const char *profileName); + +T2ERROR disableProfile(const char *profileName, bool *isDeleteRequired); + +T2ERROR deleteProfile(const char *profileName); + +T2ERROR deleteAllProfiles(bool delFromDisk); + +void updateMarkerComponentMap(); + +hash_map_t *getProfileHashMap(); + +void sendLogUploadInterruptToScheduler(); + +void NotifyTimeout(const char* profileName, bool isClearSeekMap); + +void getMarkerCompRbusSub(bool subscription); + +bool isProfileEnabled(const char *profileName); + +T2ERROR registerTriggerConditionConsumer(); + +T2ERROR triggerReportOnCondtion(const char *referenceName, const char *referenceValue); + +unsigned int getMinThresholdDuration(char *profileName); + +void reportGenerationCompleteReceiver(char* profileName); + +void NotifySchedulerstart(char* profileName, bool isschedulerstarted); + +T2ERROR appendTriggerCondition (Profile *tempProfile, const char *referenceName, const char *referenceValue); + +T2ERROR ReportProfiles_addReportProfile(Profile *profile); +T2ERROR RemovePreRPfromDisk(const char* path, hash_map_t *map); +#endif /* _PROFILE_H_ */ From 50b58b42e8a6be2c558def3f71c707a06916979d Mon Sep 17 00:00:00 2001 From: Aravindan NC <35158113+AravindanNC@users.noreply.github.com> Date: Wed, 15 Apr 2026 15:14:04 -0400 Subject: [PATCH 6/7] Update profilexconf.c --- source/bulkdata/profilexconf.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/source/bulkdata/profilexconf.c b/source/bulkdata/profilexconf.c index f3250d91..db678534 100644 --- a/source/bulkdata/profilexconf.c +++ b/source/bulkdata/profilexconf.c @@ -50,7 +50,7 @@ static ProfileXConf *singleProfile = NULL; * Kept as mutex (not rwlock) because pthread_cond_wait requires pthread_mutex_t. * Lock hierarchy: L0 (same level as profileListLock in profile.c). */ -static pthread_mutex_t xconfProfileLock; +static pthread_mutex_t xconfProfileLock = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t reuseThread; static bool reportThreadExits = false; @@ -613,18 +613,13 @@ T2ERROR ProfileXConf_init(bool checkPreviousSeek) Config *config = NULL; initialized = true; - if(pthread_mutex_init(&xconfProfileLock, NULL) != 0) - { - T2Error("%s Mutex init has failed\n", __FUNCTION__); - return T2ERROR_FAILURE; - } /* Initialize condition variable at module init to prevent race where * ProfileXConf_notifyTimeout signals before CollectAndReportXconf initializes it. */ if(pthread_cond_init(&reuseThread, NULL) != 0) { T2Error("%s Condition variable init has failed\n", __FUNCTION__); - pthread_mutex_destroy(&xconfProfileLock); + initialized = false; return T2ERROR_FAILURE; } Vector_Create(&configList); From dee29f9258a2e6d87ef03375ec289229c21d00a8 Mon Sep 17 00:00:00 2001 From: Aravindan NC <35158113+AravindanNC@users.noreply.github.com> Date: Wed, 15 Apr 2026 15:53:06 -0400 Subject: [PATCH 7/7] Update profile.c --- source/bulkdata/profile.c | 2141 ++++++++++++++++++++++++++++++++++--- 1 file changed, 2011 insertions(+), 130 deletions(-) diff --git a/source/bulkdata/profile.c b/source/bulkdata/profile.c index 8401cf92..f141c342 100644 --- a/source/bulkdata/profile.c +++ b/source/bulkdata/profile.c @@ -17,142 +17,2023 @@ * limitations under the License. */ -#ifndef _PROFILE_H_ -#define _PROFILE_H_ - #include -#include -#include +#include +#include +#include +#include +#include +#include -#include "t2collection.h" -#include "telemetry2_0.h" +#include "profile.h" #include "reportprofiles.h" #include "t2eventreceiver.h" -#include "t2common.h" +#include "t2markers.h" +#include "t2log_wrapper.h" +#include "busInterface.h" +#include "curlinterface.h" +#include "rbusmethodinterface.h" +#include "scheduler.h" +#include "persistence.h" #include "vector.h" -#include "reportgen.h" +#include "dcautil.h" +#include "t2parser.h" +#include "rbusInterface.h" #include "legacyutils.h" -typedef struct _JSONEncoding +#if defined(PRIVACYMODES_CONTROL) +#include "rdkservices_privacyutils.h" +#endif + +#define MAX_LEN 256 + +#ifdef GTEST_ENABLE +#define sendReportOverHTTP __wrap_sendReportOverHTTP +#define sendCachedReportsOverHTTP __wrap_sendCachedReportsOverHTTP +#endif + +static bool initialized = false; +static Vector *profileList; +static pthread_mutex_t profileListLock; // L0: protects profileList (rdlock for reads, wrlock for writes) +static pthread_mutex_t reportLock; + +static pthread_mutex_t triggerConditionQueMutex = PTHREAD_MUTEX_INITIALIZER; +static queue_t *triggerConditionQueue = NULL; + +typedef struct __triggerConditionObj__ { - JSONFormat reportFormat; - TimeStampFormat tsFormat; -} JSONEncoding; + char referenceName[MAX_LEN]; + char referenceValue[MAX_LEN]; +} triggerConditionObj ; + +static void freeRequestURIparam(void *data) +{ + if(data != NULL) + { + HTTPReqParam *hparam = (HTTPReqParam *)data; + if(hparam->HttpName) + { + free(hparam->HttpName); + } + if(hparam->HttpRef) + { + free(hparam->HttpRef); + } + if(hparam->HttpValue) + { + free(hparam->HttpValue); + } + free(hparam); + } +} + +static void freeReportProfileConfig(void *data) +{ + if(data != NULL) + { + Config *config = (Config *)data; + + if(config->name) + { + free(config->name); + } + if(config->configData) + { + free(config->configData); + } + + free(config); + } +} + +static void freeProfile(void *data) +{ + T2Debug("%s ++in \n", __FUNCTION__); + if(data != NULL) + { + Profile *profile = (Profile *)data; + if(profile->name) + { + free(profile->name); + } + if(profile->hash) + { + free(profile->hash); + } + if(profile->protocol) + { + free(profile->protocol); + } + if(profile->encodingType) + { + free(profile->encodingType); + } + if(profile->RootName) + { + free(profile->RootName); + } + if(profile->Description) + { + free(profile->Description); + } + if(profile->version) + { + free(profile->version); + } + if(profile->jsonEncoding) + { + free(profile->jsonEncoding); + } + if(profile->timeRef) + { + free(profile->timeRef); + } + if(profile->t2HTTPDest) + { + free(profile->t2HTTPDest->URL); + if(profile->t2HTTPDest->RequestURIparamList) + { + Vector_Destroy(profile->t2HTTPDest->RequestURIparamList, freeRequestURIparam); + } + free(profile->t2HTTPDest); + } + if(profile->t2RBUSDest) + { + if(profile->t2RBUSDest->rbusMethodName) + { + memset(profile->t2RBUSDest->rbusMethodName, 0, strlen(profile->t2RBUSDest->rbusMethodName)); + free(profile->t2RBUSDest->rbusMethodName); + profile->t2RBUSDest->rbusMethodName = NULL ; + } + if(profile->t2RBUSDest->rbusMethodParamList) + { + // TBD determine whether data is simple string before passing free as cleanup function + Vector_Destroy(profile->t2RBUSDest->rbusMethodParamList, free); + } + free(profile->t2RBUSDest); + } + if(profile->eMarkerList) + { + Vector_Destroy(profile->eMarkerList, freeEMarker); + } + if(profile->gMarkerList) + { + Vector_Destroy(profile->gMarkerList, freeGMarker); + } + if(profile->topMarkerList) + { + Vector_Destroy(profile->topMarkerList, freeGMarker); + } + if(profile->paramList) + { + Vector_Destroy(profile->paramList, freeParam); + } + if (profile->staticParamList) + { + Vector_Destroy(profile->staticParamList, freeStaticParam); + } + if(profile->triggerConditionList) + { + Vector_Destroy(profile->triggerConditionList, freeTriggerCondition); + } + + if(profile->cachedReportList) + { + Vector_Destroy(profile->cachedReportList, free); + profile->cachedReportList = NULL; + } + if(profile->jsonReportObj) + { + cJSON_Delete(profile->jsonReportObj); + profile->jsonReportObj = NULL; + } + free(profile); + } + T2Debug("%s ++out \n", __FUNCTION__); +} + +static T2ERROR getProfile(const char *profileName, Profile **profile) +{ + size_t profileIndex = 0; + Profile *tempProfile = NULL; + T2Debug("%s ++in\n", __FUNCTION__); + if(profileName == NULL) + { + T2Error("profileName is null\n"); + return T2ERROR_FAILURE; + } + for(; profileIndex < Vector_Size(profileList); profileIndex++) + { + tempProfile = (Profile *)Vector_At(profileList, profileIndex); + if(strcmp(tempProfile->name, profileName) == 0) + { + *profile = tempProfile; + T2Debug("%s --out\n", __FUNCTION__); + return T2ERROR_SUCCESS; + } + } + T2Error("Profile with Name : %s not found\n", profileName); + return T2ERROR_PROFILE_NOT_FOUND; +} + +static T2ERROR initJSONReportProfile(cJSON** jsonObj, cJSON **valArray, char *rootname) +{ + *jsonObj = cJSON_CreateObject(); + if(*jsonObj == NULL) + { + T2Error("Failed to create cJSON object\n"); + return T2ERROR_FAILURE; + } + cJSON_AddItemToObject(*jsonObj, rootname, *valArray = cJSON_CreateArray()); + + + return T2ERROR_SUCCESS; +} + +static void calculateMaxUploadLatency(Profile *profile, time_t *maxuploadinmilliSec, time_t *maxuploadinSec) +{ + unsigned int random_value = 0; + // Ensure maxUploadLatency > 1 to avoid modulo by zero + if(profile->maxUploadLatency > 1) + { + int urandom = -1; + urandom = open("/dev/urandom", O_RDONLY); + if(urandom != -1 && read(urandom, &random_value, sizeof(random_value)) == sizeof(random_value)) + { + *maxuploadinmilliSec = random_value % (profile->maxUploadLatency - 1); + if(close(urandom) == -1) + { + T2Error("Failed to close /dev/urandom: %s\n", strerror(errno)); + } + } + else + { + if(urandom != -1) + { + if(close(urandom) == -1) + { + T2Error("Failed to close /dev/urandom: %s\n", strerror(errno)); + } + } + *maxuploadinmilliSec = (unsigned int)(time(0) % (profile->maxUploadLatency - 1)); + } + } + else + { + // If maxUploadLatency is 1, set maxuploadinmilliSec to 0 + *maxuploadinmilliSec = 0; + } + *maxuploadinSec = (*maxuploadinmilliSec + 1) / 1000; +} + +T2ERROR profileWithNameExists(const char *profileName, bool *bProfileExists) +{ + size_t profileIndex = 0; + Profile *tempProfile = NULL; + T2Debug("%s ++in\n", __FUNCTION__); + if(!initialized) + { + T2Error("profile list is not initialized yet, ignoring\n"); + return T2ERROR_FAILURE; + } + if(profileName == NULL) + { + T2Error("profileName is null\n"); + *bProfileExists = false; + return T2ERROR_FAILURE; + } + pthread_mutex_lock(&profileListLock); + for(; profileIndex < Vector_Size(profileList); profileIndex++) + { + tempProfile = (Profile *)Vector_At(profileList, profileIndex); + if(strcmp(tempProfile->name, profileName) == 0) + { + *bProfileExists = true; + pthread_mutex_unlock(&profileListLock); + return T2ERROR_SUCCESS; + } + } + *bProfileExists = false; + pthread_mutex_unlock(&profileListLock); + T2Error("Profile with Name : %s not found\n", profileName); + return T2ERROR_PROFILE_NOT_FOUND; +} + +void getMarkerCompRbusSub(bool subscription) +{ + T2Debug("%s ++in\n", __FUNCTION__); + Vector* eventMarkerListForComponent = NULL; + getComponentMarkerList(T2REPORTCOMPONENT, (void**)&eventMarkerListForComponent); + int length = Vector_Size(eventMarkerListForComponent); + int i; + if(length > 0) + { + for(i = 0; i < length; ++i ) + { + char* markerName = (char *) Vector_At(eventMarkerListForComponent, i); + if(markerName) + { + int ret = T2RbusReportEventConsumer(markerName, subscription); + T2Debug("%d T2RbusEventReg with name = %s: subscription = %s ret %d \n", i, markerName, (subscription ? "Subscribe" : "Un-Subscribe"), ret); + } + else + { + T2Error("Error while retrieving Marker Name at index : %d \n", i); + } + } + if(eventMarkerListForComponent != NULL) + { + Vector_Destroy(eventMarkerListForComponent, free); + } + } + //CID 255490: Resource leak (RESOURCE_LEAK) + else + { + if(eventMarkerListForComponent != NULL) + { + Vector_Destroy(eventMarkerListForComponent, free); + } + } + T2Debug("%s --out\n", __FUNCTION__); +} + +static void* CollectAndReport(void* data) +{ + T2Debug("%s ++in\n", __FUNCTION__); + if(data == NULL) + { + T2Error("data passed is NULL can't identify the profile, existing from CollectAndReport\n"); + return NULL; + } + Profile* profile = (Profile *)data; + pthread_mutex_init(&profile->reuseThreadMutex, NULL); + pthread_cond_init(&profile->reuseThread, NULL); + pthread_mutex_lock(&profile->reuseThreadMutex); + profile->restartRequested = false; + profile->threadExists = true; + //GrepSeekProfile *GPF = profile->GrepSeekProfle; + do + { + T2Info("%s while Loop -- START \n", __FUNCTION__); + pthread_mutex_lock(&profile->reportInProgressMutex); + profile->reportInProgress = true; + pthread_cond_signal(&profile->reportInProgressCond); + pthread_mutex_unlock(&profile->reportInProgressMutex); + pthread_mutex_unlock(&profile->reuseThreadMutex); + + int count = profile->grepSeekProfile->execCounter; + + Vector *profileParamVals = NULL; + cJSON *valArray = NULL; + char* jsonReport = NULL; + cJSON *triggercondition = NULL; + time_t maxuploadinSec = 0; + time_t maxuploadinmilliSec = 0; + int n = 0; + struct timespec startTime; + struct timespec endTime; + struct timespec elapsedTime; + char* customLogPath = NULL; + int clockReturn = 0; + + T2ERROR ret = T2ERROR_FAILURE; + if( profile->name == NULL || profile->encodingType == NULL || profile->protocol == NULL ) + { + T2Error("Incomplete profile parameters\n"); + if(profile->triggerReportOnCondition) + { + T2Info(" Unlock trigger condition mutex and set report on condition to false \n"); + profile->triggerReportOnCondition = false ; + pthread_mutex_unlock(&profile->triggerCondMutex); + } + else + { + T2Debug(" profile->triggerReportOnCondition is not set \n"); + } + pthread_mutex_lock(&profile->reuseThreadMutex); + pthread_mutex_lock(&profile->reportInProgressMutex); + profile->reportInProgress = false; + pthread_cond_signal(&profile->reportInProgressCond); + pthread_mutex_unlock(&profile->reportInProgressMutex); + pthread_mutex_unlock(&profile->reuseThreadMutex); + //return NULL; + goto reportThreadEnd; + } + + T2Info("%s ++in profileName : %s\n", __FUNCTION__, profile->name); + + + clockReturn = clock_gettime(CLOCK_MONOTONIC, &startTime); + if( !strcmp(profile->encodingType, "JSON") || !strcmp(profile->encodingType, "MessagePack")) + { + JSONEncoding *jsonEncoding = profile->jsonEncoding; + if (jsonEncoding->reportFormat != JSONRF_KEYVALUEPAIR) + { + //TODO: Support 'ObjectHierarchy' format in RDKB-26154. + T2Error("Only JSON name-value pair format is supported \n"); + if(profile->triggerReportOnCondition) + { + T2Info(" Unlock trigger condition mutex and set report on condition to false \n"); + profile->triggerReportOnCondition = false ; + pthread_mutex_unlock(&profile->triggerCondMutex); + } + else + { + T2Debug(" profile->triggerReportOnCondition is not set \n"); + } + pthread_mutex_lock(&profile->reuseThreadMutex); + pthread_mutex_lock(&profile->reportInProgressMutex); + profile->reportInProgress = false; + pthread_cond_signal(&profile->reportInProgressCond); + pthread_mutex_unlock(&profile->reportInProgressMutex); + pthread_mutex_unlock(&profile->reuseThreadMutex); + //return NULL; + goto reportThreadEnd; + } + // pthread_mutex_lock(&profile->triggerCondMutex); + if(profile->triggerReportOnCondition && (profile->jsonReportObj != NULL)) + { + triggercondition = profile->jsonReportObj; + profile->jsonReportObj = NULL; + } + if(T2ERROR_SUCCESS != initJSONReportProfile(&profile->jsonReportObj, &valArray, profile->RootName)) + { + T2Error("Failed to initialize JSON Report\n"); + pthread_mutex_lock(&profile->reuseThreadMutex); + pthread_mutex_lock(&profile->reportInProgressMutex); + profile->reportInProgress = false; + pthread_cond_signal(&profile->reportInProgressCond); + pthread_mutex_unlock(&profile->reportInProgressMutex); + pthread_mutex_unlock(&profile->reuseThreadMutex); + //pthread_mutex_unlock(&profile->triggerCondMutex); + if(profile->triggerReportOnCondition) + { + T2Info(" Unlock trigger condition mutex and set report on condition to false \n"); + profile->triggerReportOnCondition = false; + pthread_mutex_unlock(&profile->triggerCondMutex); + if(profile->callBackOnReportGenerationComplete) + { + profile->callBackOnReportGenerationComplete(profile->name); + } + } + //return NULL; + goto reportThreadEnd; + } + else + { +#ifdef PERSIST_LOG_MON_REF + if(profile->checkPreviousSeek) + { + cJSON *arrayItem = NULL; + arrayItem = cJSON_CreateObject(); + cJSON_AddStringToObject(arrayItem, PREVIOUS_LOG, PREVIOUS_LOGS_VAL); + cJSON_AddItemToArray(valArray, arrayItem); + customLogPath = PREVIOUS_LOGS_PATH; + profile->bClearSeekMap = true; + T2Debug("Adding Previous Logs Header to JSON report\n"); + } +#endif + if(profile->staticParamList != NULL && Vector_Size(profile->staticParamList) > 0) + { + T2Debug(" Adding static Parameter Values to Json report\n"); + encodeStaticParamsInJSON(valArray, profile->staticParamList); + } + if(profile->paramList != NULL && Vector_Size(profile->paramList) > 0) + { + T2Debug("Fetching TR-181 Object/Parameter Values\n"); + profileParamVals = getProfileParameterValues(profile->paramList, count); + if(profileParamVals != NULL) + { + encodeParamResultInJSON(valArray, profile->paramList, profileParamVals); + } + Vector_Destroy(profileParamVals, freeProfileValues); + } + if(profile->topMarkerList != NULL && Vector_Size(profile->topMarkerList) > 0) + { + processTopPattern(profile->name, profile->topMarkerList, 0); + encodeTopResultInJSON(valArray, profile->topMarkerList); + } + if(profile->gMarkerList != NULL && Vector_Size(profile->gMarkerList) > 0) + { + getGrepResults(&(profile->grepSeekProfile), profile->gMarkerList, profile->bClearSeekMap, false, customLogPath); // Passing 4th argument as false so that it doesn't check rotated logs for the first reporting after bootup for multiprofiles. + encodeGrepResultInJSON(valArray, profile->gMarkerList); + } + if(profile->eMarkerList != NULL && Vector_Size(profile->eMarkerList) > 0) + { + pthread_mutex_lock(&profile->eventMutex); + encodeEventMarkersInJSON(valArray, profile->eMarkerList); + pthread_mutex_unlock(&profile->eventMutex); + } + if(profile->triggerReportOnCondition && (triggercondition != NULL)) + { + cJSON_AddItemToArray(valArray, triggercondition); + } + ret = prepareJSONReport(profile->jsonReportObj, &jsonReport); + destroyJSONReport(profile->jsonReportObj); + profile->jsonReportObj = NULL; + if(ret != T2ERROR_SUCCESS) + { + T2Error("Unable to generate report for : %s\n", profile->name); + pthread_mutex_lock(&profile->reuseThreadMutex); + pthread_mutex_lock(&profile->reportInProgressMutex); + profile->reportInProgress = false; + pthread_cond_signal(&profile->reportInProgressCond); + pthread_mutex_unlock(&profile->reportInProgressMutex); + pthread_mutex_unlock(&profile->reuseThreadMutex); + if(profile->triggerReportOnCondition) + { + profile->triggerReportOnCondition = false ; + pthread_mutex_unlock(&profile->triggerCondMutex); + + if(profile->callBackOnReportGenerationComplete) + { + profile->callBackOnReportGenerationComplete(profile->name); + } + } + else + { + T2Debug(" profile->triggerReportOnCondition is not set \n"); + } + //return NULL; + goto reportThreadEnd; + } +#ifdef PERSIST_LOG_MON_REF + if(profile->saveSeekConfig) + { + saveSeekConfigtoFile(profile->name, profile->grepSeekProfile); + } + if(profile->checkPreviousSeek) + { + T2Info("Previous Logs report is sent clear the previousSeek flag\n"); + profile->checkPreviousSeek = false; + customLogPath = NULL; + profile->bClearSeekMap = false; + } +#endif + long size = strlen(jsonReport); + T2Info("cJSON Report = %s\n", jsonReport); + cJSON *root = cJSON_Parse(jsonReport); + if(root != NULL) + { + cJSON *array = cJSON_GetObjectItem(root, profile->RootName); + if(cJSON_GetArraySize(array) == 0) + { + T2Warning("Array size of Report is %d. Report is empty. Cannot send empty report\n", cJSON_GetArraySize(array)); + pthread_mutex_lock(&profile->reuseThreadMutex); + pthread_mutex_lock(&profile->reportInProgressMutex); + profile->reportInProgress = false; + pthread_cond_signal(&profile->reportInProgressCond); + pthread_mutex_unlock(&profile->reportInProgressMutex); + pthread_mutex_unlock(&profile->reuseThreadMutex); + if(profile->triggerReportOnCondition) + { + T2Info(" Unlock trigger condition mutex and set report on condition to false \n"); + profile->triggerReportOnCondition = false ; + pthread_mutex_unlock(&profile->triggerCondMutex); + if(profile->callBackOnReportGenerationComplete) + { + profile->callBackOnReportGenerationComplete(profile->name); + } + } + else + { + T2Debug(" profile->triggerReportOnCondition is not set \n"); + } + cJSON_Delete(root); + //return NULL; + goto reportThreadEnd; + } + cJSON_Delete(root); + } + + T2Info("Report Size = %ld\n", size); + if(size > DEFAULT_MAX_REPORT_SIZE) + { + T2Warning("Report size is exceeding the max limit : %d\n", DEFAULT_MAX_REPORT_SIZE); + } + if(profile->maxUploadLatency > 0) + { + pthread_mutex_lock(&profile->reuseThreadMutex); + memset(&profile->maxlatencyTime, 0, sizeof(struct timespec)); + memset(&profile->currentTime, 0, sizeof(struct timespec)); + clock_gettime(CLOCK_REALTIME, &profile->currentTime); + profile->maxlatencyTime.tv_sec = profile->currentTime.tv_sec; + pthread_mutex_unlock(&profile->reuseThreadMutex); + pthread_mutex_init(&profile->reportMutex, NULL); + pthread_cond_init(&profile->reportcond, NULL); + calculateMaxUploadLatency(profile, &maxuploadinmilliSec, &maxuploadinSec); + } + if( strcmp(profile->protocol, "HTTP") == 0 || strcmp(profile->protocol, "RBUS_METHOD") == 0 ) + { + char *httpUrl = NULL ; + if ( strcmp(profile->protocol, "HTTP") == 0 ) + { + httpUrl = prepareHttpUrl(profile->t2HTTPDest); /* Append URL with http properties */ + if(profile->maxUploadLatency > 0) + { + T2Info("waiting for %ld sec of macUploadLatency\n", (long) maxuploadinSec); + struct timespec timeout; + pthread_mutex_lock(&profile->reuseThreadMutex); + profile->maxlatencyTime.tv_sec += maxuploadinSec; + timeout = profile->maxlatencyTime; + pthread_mutex_unlock(&profile->reuseThreadMutex); + pthread_mutex_lock(&profile->reportMutex); + while (profile->enable && n != ETIMEDOUT) + { + n = pthread_cond_timedwait(&profile->reportcond, &profile->reportMutex, &timeout); + } + if(n == ETIMEDOUT) + { + T2Info("TIMEOUT for maxUploadLatency of profile %s\n", profile->name); + ret = sendReportOverHTTP(httpUrl, jsonReport); + } + else if(n == 0) + { + T2Info("Profile : %s signaled before timeout, skipping report upload\n", profile->name); + } + else + { + T2Error("Profile : %s pthread_cond_timedwait ERROR!!!\n", profile->name); + pthread_mutex_unlock(&profile->reportMutex); + pthread_cond_destroy(&profile->reportcond); + if(httpUrl) + { + free(httpUrl); + httpUrl = NULL; + } + pthread_mutex_lock(&profile->reuseThreadMutex); + pthread_mutex_lock(&profile->reportInProgressMutex); + profile->reportInProgress = false; + pthread_cond_signal(&profile->reportInProgressCond); + pthread_mutex_unlock(&profile->reportInProgressMutex); + pthread_mutex_unlock(&profile->reuseThreadMutex); + if(profile->triggerReportOnCondition) + { + T2Info(" Unlock trigger condition mutex and set report on condition to false \n"); + profile->triggerReportOnCondition = false ; + pthread_mutex_unlock(&profile->triggerCondMutex); + + if(profile->callBackOnReportGenerationComplete != NULL) + { + T2Debug("Calling callback function profile->callBackOnReportGenerationComplete \n"); + profile->callBackOnReportGenerationComplete(profile->name); + } + } + else + { + T2Debug(" profile->triggerReportOnCondition is not set \n"); + } + //return NULL; + goto reportThreadEnd; + } + pthread_mutex_unlock(&profile->reportMutex); + pthread_cond_destroy(&profile->reportcond); + pthread_mutex_destroy(&profile->reportMutex); + } + else + { + ret = sendReportOverHTTP(httpUrl, jsonReport); + } + } + else + { + if(profile->maxUploadLatency > 0 ) + { + T2Info("waiting for %ld sec of macUploadLatency\n", (long) maxuploadinSec); + struct timespec timeout; + pthread_mutex_lock(&profile->reuseThreadMutex); + profile->maxlatencyTime.tv_sec += maxuploadinSec; + timeout = profile->maxlatencyTime; + pthread_mutex_unlock(&profile->reuseThreadMutex); + pthread_mutex_lock(&profile->reportMutex); + while (profile->enable && n != ETIMEDOUT) + { + n = pthread_cond_timedwait(&profile->reportcond, &profile->reportMutex, &timeout); + } + if(n == ETIMEDOUT) + { + T2Info("TIMEOUT for maxUploadLatency of profile %s\n", profile->name); + ret = sendReportsOverRBUSMethod(profile->t2RBUSDest->rbusMethodName, profile->t2RBUSDest->rbusMethodParamList, jsonReport); + } + else if(n == 0) + { + T2Info("Profile : %s signaled before timeout, skipping report upload\n", profile->name); + } + else + { + T2Error("Profile : %s pthread_cond_timedwait ERROR!!!\n", profile->name); + pthread_mutex_unlock(&profile->reportMutex); + pthread_cond_destroy(&profile->reportcond); + pthread_mutex_lock(&profile->reuseThreadMutex); + pthread_mutex_lock(&profile->reportInProgressMutex); + profile->reportInProgress = false; + pthread_cond_signal(&profile->reportInProgressCond); + pthread_mutex_unlock(&profile->reportInProgressMutex); + pthread_mutex_unlock(&profile->reuseThreadMutex); + if(profile->triggerReportOnCondition) + { + T2Info(" Unlock trigger condition mutex and set report on condition to false \n"); + profile->triggerReportOnCondition = false ; + pthread_mutex_unlock(&profile->triggerCondMutex); + + if(profile->callBackOnReportGenerationComplete) + { + T2Debug("Calling callback function profile->callBackOnReportGenerationComplete \n"); + profile->callBackOnReportGenerationComplete(profile->name); + } + } + else + { + T2Debug(" profile->triggerReportOnCondition is not set \n"); + } + //return NULL; + goto reportThreadEnd; + } + pthread_mutex_unlock(&profile->reportMutex); + pthread_cond_destroy(&profile->reportcond); + } + else + { + ret = sendReportsOverRBUSMethod(profile->t2RBUSDest->rbusMethodName, profile->t2RBUSDest->rbusMethodParamList, jsonReport); + } + } + if((ret == T2ERROR_FAILURE && strcmp(profile->protocol, "HTTP") == 0) || ret == T2ERROR_NO_RBUS_METHOD_PROVIDER) + { + T2Debug("Vector list size = %lu\n", (unsigned long) Vector_Size(profile->cachedReportList)); + if(profile->cachedReportList != NULL && Vector_Size(profile->cachedReportList) >= MAX_CACHED_REPORTS) + { + while(Vector_Size(profile->cachedReportList) > MAX_CACHED_REPORTS) + { + int pos = Vector_Size(profile->cachedReportList); + T2Info("Max Cached Reports Limit Exceeded, Removing the extra reports\n"); + char *extraCachedreport = (char*) Vector_At(profile->cachedReportList, (pos - 1)); + Vector_RemoveItem(profile->cachedReportList, (void*) extraCachedreport, NULL); + free(extraCachedreport); + } + T2Info("Max Cached Reports Limit Reached, Overwriting third recent report\n"); + char *thirdCachedReport = (char*) Vector_At(profile->cachedReportList, MAX_CACHED_REPORTS - 3); + Vector_RemoveItem(profile->cachedReportList, (void*) thirdCachedReport, NULL); + free(thirdCachedReport); + } + // Before caching the report, add "REPORT_TYPE": "CACHED" + tagReportAsCached(&jsonReport); + Vector_PushBack(profile->cachedReportList, jsonReport); + + T2Info("Report Cached, No. of reportes cached = %lu\n", (unsigned long )Vector_Size(profile->cachedReportList)); + // Save messages from profile->cachedReportList to a file in persistent location . + saveCachedReportToPersistenceFolder(profile->name, profile->cachedReportList); + + if(strcmp(profile->protocol, "RBUS_METHOD") == 0) + { + profile->SendErr++; + if(profile->SendErr > 3 && !(rbusCheckMethodExists(profile->t2RBUSDest->rbusMethodName))) //to delete the profile in the next CollectAndReport or triggercondition + { + T2Debug("RBUS_METHOD doesn't exists after 3 retries\n"); + pthread_mutex_lock(&profile->reuseThreadMutex); + pthread_mutex_lock(&profile->reportInProgressMutex); + profile->reportInProgress = false; + pthread_cond_signal(&profile->reportInProgressCond); + pthread_mutex_unlock(&profile->reportInProgressMutex); + pthread_mutex_unlock(&profile->reuseThreadMutex); + if(profile->triggerReportOnCondition) + { + profile->triggerReportOnCondition = false ; + pthread_mutex_unlock(&profile->triggerCondMutex); + if(profile->callBackOnReportGenerationComplete) + { + profile->callBackOnReportGenerationComplete(profile->name); + } + } + else + { + T2Debug(" profile->triggerReportOnCondition is not set \n"); + } + T2Error("ERROR: no method provider; profile will be deleted: %s %s\n", profile->name, + profile->t2RBUSDest->rbusMethodName); + if(T2ERROR_SUCCESS != deleteProfile(profile->name)) + { + T2Error("Failed to delete profile after RBUS_METHOD failures: %s\n", profile->name); + T2Info("%s --out\n", __FUNCTION__); + //return NULL; + goto reportThreadEnd; + } + T2Info("%s --out\n", __FUNCTION__); + //return NULL; + goto reportThreadEnd; + } + } + } + else if(profile->cachedReportList != NULL && Vector_Size(profile->cachedReportList) > 0) + { + T2Info("Trying to send %lu cached reports\n", (unsigned long )Vector_Size(profile->cachedReportList)); + if(strcmp(profile->protocol, "HTTP") == 0) + { + ret = sendCachedReportsOverHTTP(httpUrl, profile->cachedReportList); + } + else + { + ret = sendCachedReportsOverRBUSMethod(profile->t2RBUSDest->rbusMethodName, profile->t2RBUSDest->rbusMethodParamList, + profile->cachedReportList); + } + + if(ret == T2ERROR_SUCCESS) + { + removeProfileFromDisk(CACHED_MESSAGE_PATH, profile->name); + } + } + if(httpUrl) + { + free(httpUrl); + httpUrl = NULL; + } + } + else + { + T2Error("Unsupported report send protocol : %s\n", profile->protocol); + } + } + } + else + { + T2Error("Unsupported encoding format : %s\n", profile->encodingType); + } + clockReturn |= clock_gettime(CLOCK_MONOTONIC, &endTime); + if(clockReturn) + { + T2Warning("Failed to get time from clock_gettime()"); + } + else + { + getLapsedTime(&elapsedTime, &endTime, &startTime); + T2Info("Elapsed Time for : %s = %lu.%lu (Sec.NanoSec)\n", profile->name, (unsigned long )elapsedTime.tv_sec, elapsedTime.tv_nsec); + } + if(ret == T2ERROR_SUCCESS && jsonReport) + { + free(jsonReport); + jsonReport = NULL; + } + + pthread_mutex_lock(&profile->reuseThreadMutex); + pthread_mutex_lock(&profile->reportInProgressMutex); + profile->reportInProgress = false; + pthread_cond_signal(&profile->reportInProgressCond); + pthread_mutex_unlock(&profile->reportInProgressMutex); + pthread_mutex_unlock(&profile->reuseThreadMutex); + if(profile->triggerReportOnCondition) + { + T2Info(" Unlock trigger condition mutex and set report on condition to false \n"); + profile->triggerReportOnCondition = false ; + pthread_mutex_unlock(&profile->triggerCondMutex); + + if(profile->callBackOnReportGenerationComplete) + { + T2Debug("Calling callback function profile->callBackOnReportGenerationComplete \n"); + profile->callBackOnReportGenerationComplete(profile->name); + } + } + else + { + T2Debug(" profile->triggerReportOnCondition is not set \n"); + } +reportThreadEnd : + T2Info("%s while Loop -- END; wait for restart event\n", __FUNCTION__); + T2Info("%s --out\n", __FUNCTION__); + pthread_mutex_lock(&profile->reuseThreadMutex); + while(profile->enable && !profile->restartRequested) + { + pthread_cond_wait(&profile->reuseThread, &profile->reuseThreadMutex); + } + profile->restartRequested = false; + } + while(profile->enable); + pthread_mutex_unlock(&profile->reuseThreadMutex); + T2Info("%s --out Exiting collect and report Thread\n", __FUNCTION__); + pthread_mutex_lock(&profile->reuseThreadMutex); + pthread_mutex_lock(&profile->reportInProgressMutex); + profile->reportInProgress = false; + pthread_cond_signal(&profile->reportInProgressCond); + pthread_mutex_unlock(&profile->reportInProgressMutex); + pthread_mutex_unlock(&profile->reuseThreadMutex); + pthread_mutex_lock(&profile->reuseThreadMutex); + profile->threadExists = false; + pthread_mutex_unlock(&profile->reuseThreadMutex); + pthread_mutex_destroy(&profile->reuseThreadMutex); + pthread_cond_destroy(&profile->reuseThread); + return NULL; +} + +void NotifyTimeout(const char* profileName, bool isClearSeekMap) +{ + T2Debug("%s ++in\n", __FUNCTION__); + pthread_mutex_lock(&profileListLock); + + Profile *profile = NULL; + if(T2ERROR_SUCCESS != getProfile(profileName, &profile)) + { + T2Error("Profile : %s not found\n", profileName); + pthread_mutex_unlock(&profileListLock); + return ; + } + + pthread_mutex_unlock(&profileListLock); + T2Info("%s: profile %s is in %s state\n", __FUNCTION__, profileName, profile->enable ? "Enabled" : "Disabled"); + pthread_mutex_lock(&profile->reportInProgressMutex); + if(profile->enable && !profile->reportInProgress) + { + profile->reportInProgress = true; + profile->bClearSeekMap = isClearSeekMap; + pthread_mutex_unlock(&profile->reportInProgressMutex); + + /* Read threadExists under reuseThreadMutex for proper synchronization. + * threadExists is written under reuseThreadMutex in CollectAndReport, + * so it must also be read under the same mutex to avoid a data race. + * Combine the read and the signal within the same lock to prevent a + * race between reading threadExists and signaling/creating the thread. */ + pthread_mutex_lock(&profile->reuseThreadMutex); + if (profile->threadExists) + { + T2Info("Signal Thread To restart\n"); + profile->restartRequested = true; + pthread_cond_signal(&profile->reuseThread); + pthread_mutex_unlock(&profile->reuseThreadMutex); + } + else + { + pthread_mutex_unlock(&profile->reuseThreadMutex); + pthread_create(&profile->reportThread, NULL, CollectAndReport, (void*)profile); + } + } + else + { + T2Warning("Either profile is disabled or report generation still in progress - ignoring the request\n"); + pthread_mutex_unlock(&profile->reportInProgressMutex); + } + T2Debug("%s --out\n", __FUNCTION__); +} + +T2ERROR Profile_storeMarkerEvent(const char *profileName, T2Event *eventInfo) +{ + T2Debug("%s ++in\n", __FUNCTION__); + + pthread_mutex_lock(&profileListLock); + Profile *profile = NULL; + if(T2ERROR_SUCCESS != getProfile(profileName, &profile)) + { + T2Error("Profile : %s not found\n", profileName); + pthread_mutex_unlock(&profileListLock); + return T2ERROR_FAILURE; + } + pthread_mutex_unlock(&profileListLock); + if(!profile->enable) + { + T2Warning("Profile : %s is disabled, ignoring the event\n", profileName); + return T2ERROR_FAILURE; + } + size_t eventIndex = 0; + EventMarker *lookupEvent = NULL; + for(; eventIndex < Vector_Size(profile->eMarkerList); eventIndex++) + { + EventMarker *tempEventMarker = (EventMarker *)Vector_At(profile->eMarkerList, eventIndex); + if(!strcmp(tempEventMarker->markerName, eventInfo->name)) + { + lookupEvent = tempEventMarker; + break; + } + } + int arraySize = 0; + if(lookupEvent != NULL) + { + char buf[256] = {'\0'}; + char timebuf[256] = {'\0'}; + time_t timestamp = 0; + pthread_mutex_lock(&profile->eventMutex); + switch(lookupEvent->mType) + { + case MTYPE_COUNTER: + lookupEvent->u.count++; + T2Debug("Increment marker count to : %d\n", lookupEvent->u.count); + if(lookupEvent->reportTimestampParam == REPORTTIMESTAMP_UNIXEPOCH) + { + if(lookupEvent->timestamp) + { + free(lookupEvent->timestamp); + lookupEvent->timestamp = NULL; + } + + timestamp = time(NULL); + if(lookupEvent->markerName_CT == NULL) + { + if(lookupEvent->alias != NULL) + { + snprintf(buf, MAX_LEN, "%s_CT", lookupEvent->alias); + } + else + { + snprintf(buf, MAX_LEN, "%s_CT", lookupEvent->markerName); + } + lookupEvent->markerName_CT = strdup(buf); + } + snprintf(timebuf, MAX_LEN, "%ld", (long) timestamp); + lookupEvent->timestamp = strdup(timebuf); + T2Debug("Timestamp for %s is %s\n", lookupEvent->markerName_CT, lookupEvent->timestamp); + } + break; + + case MTYPE_ACCUMULATE: + T2Debug("Marker type is ACCUMULATE Event Value : %s\n", eventInfo->value); + arraySize = Vector_Size(lookupEvent->u.accumulatedValues); + T2Debug("Current array size : %d \n", arraySize); + if( arraySize < MAX_ACCUMULATE) + { + Vector_PushBack(lookupEvent->u.accumulatedValues, strdup(eventInfo->value)); + T2Debug("Sucessfully added value into vector New Size : %d\n", ++arraySize); + if(lookupEvent->reportTimestampParam == REPORTTIMESTAMP_UNIXEPOCH) + { + timestamp = time(NULL); + if(lookupEvent->markerName_CT == NULL) + { + if(lookupEvent->alias != NULL) + { + snprintf(buf, MAX_LEN, "%s_CT", lookupEvent->alias); + } + else + { + snprintf(buf, MAX_LEN, "%s_CT", lookupEvent->markerName); + } + lookupEvent->markerName_CT = strdup(buf); + } + snprintf(timebuf, MAX_LEN, "%ld", (long) timestamp); + T2Debug("Timestamp for %s is %ld\n", lookupEvent->markerName_CT, (long) timestamp); + Vector_PushBack(lookupEvent->accumulatedTimestamp, strdup(timebuf)); + T2Debug("Vector_PushBack for accumulatedTimestamp is done\n"); + } + } + else if ( arraySize == MAX_ACCUMULATE ) + { + T2Warning("Max size of the array has been reached appending warning message : %s\n", MAX_ACCUMULATE_MSG); + Vector_PushBack(lookupEvent->u.accumulatedValues, strdup(MAX_ACCUMULATE_MSG)); + T2Debug("Sucessfully added warning message into vector New Size : %d\n", ++arraySize); + } + else + { + T2Warning("Max size of the array has been reached Ignore New Value\n"); + } + break; + + case MTYPE_ABSOLUTE: + default: + if(lookupEvent->u.markerValue) + { + free(lookupEvent->u.markerValue); + lookupEvent->u.markerValue = NULL; + } + + lookupEvent->u.markerValue = strdup(eventInfo->value); + T2Debug("New marker value saved : %s\n", lookupEvent->u.markerValue); + if(lookupEvent->reportTimestampParam == REPORTTIMESTAMP_UNIXEPOCH) + { + if(lookupEvent->timestamp) + { + free(lookupEvent->timestamp); + lookupEvent->timestamp = NULL; + } + + timestamp = time(NULL); + if(lookupEvent->markerName_CT == NULL) + { + if(lookupEvent->alias != NULL) + { + snprintf(buf, MAX_LEN, "%s_CT", lookupEvent->alias); + } + else + { + snprintf(buf, MAX_LEN, "%s_CT", lookupEvent->markerName); + } + lookupEvent->markerName_CT = strdup(buf); + } + snprintf(timebuf, MAX_LEN, "%ld", (long)timestamp); + lookupEvent->timestamp = strdup(timebuf); + T2Debug("Timestamp for %s is %s\n", lookupEvent->markerName_CT, lookupEvent->timestamp); + } + break; + } + pthread_mutex_unlock(&profile->eventMutex); + } + else + { + T2Error("Event name : %s value : %s\n", eventInfo->name, eventInfo->value); + T2Error("Event doens't match any marker information, shouldn't come here\n"); + return T2ERROR_FAILURE; + } + + T2Debug("%s --out\n", __FUNCTION__); + return T2ERROR_SUCCESS; +} + +T2ERROR addProfile(Profile *profile) +{ + T2Debug("%s ++in\n", __FUNCTION__); + if(!initialized) + { + T2Error("profile list is not initialized yet, ignoring\n"); + return T2ERROR_FAILURE; + } + pthread_mutex_lock(&profileListLock); + Vector_PushBack(profileList, profile); + + pthread_mutex_unlock(&profileListLock); + T2Debug("%s --out\n", __FUNCTION__); + return T2ERROR_SUCCESS; +} + +T2ERROR enableProfile(const char *profileName) +{ + T2Debug("%s ++in \n", __FUNCTION__); + if(!initialized) + { + T2Error("profile list is not initialized yet, ignoring\n"); + return T2ERROR_FAILURE; + } + pthread_mutex_lock(&profileListLock); + Profile *profile = NULL; + if(T2ERROR_SUCCESS != getProfile(profileName, &profile)) + { + T2Error("Profile : %s not found\n", profileName); + pthread_mutex_unlock(&profileListLock); + return T2ERROR_FAILURE; + } + if(profile->enable) + { + T2Info("Profile : %s is already enabled - ignoring duplicate request\n", profileName); + pthread_mutex_unlock(&profileListLock); + return T2ERROR_SUCCESS; + } + else + { + profile->enable = true; + if(pthread_mutex_init(&profile->triggerCondMutex, NULL) != 0) + { + T2Error(" %s Mutex init has failed\n", __FUNCTION__); + pthread_mutex_unlock(&profileListLock); + return T2ERROR_FAILURE; + } + if(pthread_mutex_init(&profile->reportInProgressMutex, NULL) != 0) + { + T2Error(" %s Mutex init has failed\n", __FUNCTION__); + pthread_mutex_unlock(&profileListLock); + return T2ERROR_FAILURE; + } + if(pthread_cond_init(&profile->reportInProgressCond, NULL) != 0) + { + T2Error(" %s Cond init has failed\n", __FUNCTION__); + pthread_mutex_unlock(&profileListLock); + return T2ERROR_FAILURE; + } + + size_t emIndex = 0; + EventMarker *eMarker = NULL; + for(; emIndex < Vector_Size(profile->eMarkerList); emIndex++) + { + eMarker = (EventMarker *)Vector_At(profile->eMarkerList, emIndex); + addT2EventMarker(eMarker->markerName, eMarker->compName, profile->name, eMarker->skipFreq); + } + if(registerProfileWithScheduler(profile->name, profile->reportingInterval, profile->activationTimeoutPeriod, profile->deleteonTimeout, true, profile->reportOnUpdate, profile->firstReportingInterval, profile->timeRef) != T2ERROR_SUCCESS) + { + profile->enable = false; + T2Error("Unable to register profile : %s with Scheduler\n", profileName); + pthread_mutex_unlock(&profileListLock); + return T2ERROR_FAILURE; + } + T2ER_StartDispatchThread(); + + T2Info("Successfully enabled profile : %s\n", profileName); + } + T2Debug("%s --out\n", __FUNCTION__); + pthread_mutex_unlock(&profileListLock); + return T2ERROR_SUCCESS; +} + + +void updateMarkerComponentMap() +{ + T2Debug("%s ++in\n", __FUNCTION__); + + size_t profileIndex = 0; + Profile *tempProfile = NULL; + + pthread_mutex_lock(&profileListLock); + for(; profileIndex < Vector_Size(profileList); profileIndex++) + { + tempProfile = (Profile *)Vector_At(profileList, profileIndex); + if(tempProfile->enable) + { + T2Debug("Updating component map for profile %s \n", tempProfile->name); + size_t emIndex = 0; + EventMarker *eMarker = NULL; + for(; emIndex < Vector_Size(tempProfile->eMarkerList); emIndex++) + { + eMarker = (EventMarker *)Vector_At(tempProfile->eMarkerList, emIndex); + addT2EventMarker(eMarker->markerName, eMarker->compName, tempProfile->name, eMarker->skipFreq); + } + } + } + pthread_mutex_unlock(&profileListLock); + T2Debug("%s --out\n", __FUNCTION__); +} + +T2ERROR disableProfile(const char *profileName, bool *isDeleteRequired) +{ + T2Debug("%s ++in \n", __FUNCTION__); + + if(!initialized) + { + T2Error("profile list is not initialized yet, ignoring\n"); + return T2ERROR_FAILURE; + } + + pthread_mutex_lock(&profileListLock); + Profile *profile = NULL; + if(T2ERROR_SUCCESS != getProfile(profileName, &profile)) + { + T2Error("Profile : %s not found\n", profileName); + pthread_mutex_unlock(&profileListLock); + return T2ERROR_FAILURE; + } + + if (profile->generateNow) + { + *isDeleteRequired = true; + } + else + { + profile->enable = false; + } +#ifdef PERSIST_LOG_MON_REF + removeProfileFromDisk(SEEKFOLDER, profile->name); +#endif + profile->isSchedulerstarted = false; + pthread_mutex_unlock(&profileListLock); + T2Debug("%s --out\n", __FUNCTION__); + + return T2ERROR_SUCCESS; +} + +T2ERROR deleteAllProfiles(bool delFromDisk) +{ + T2Debug("%s ++in\n", __FUNCTION__); + + int count = 0; + int profileIndex = 0; + Profile *tempProfile = NULL; + + pthread_mutex_lock(&profileListLock); + if(profileList == NULL) + { + T2Error("profile list is not initialized yet or profileList is empty, ignoring\n"); + pthread_mutex_unlock(&profileListLock); + return T2ERROR_FAILURE; + } + + count = Vector_Size(profileList); + pthread_mutex_unlock(&profileListLock); + + for(; profileIndex < count; profileIndex++) + { + pthread_mutex_lock(&profileListLock); + tempProfile = (Profile *)Vector_At(profileList, profileIndex); + tempProfile->enable = false; + tempProfile->isSchedulerstarted = false; + pthread_mutex_unlock(&profileListLock); + + if(T2ERROR_SUCCESS != unregisterProfileFromScheduler(tempProfile->name)) + { + T2Error("Profile : %s failed to unregister from scheduler\n", tempProfile->name); + } + + /* Read threadExists under reuseThreadMutex: threadExists is written under + * reuseThreadMutex in CollectAndReport, so reads must use the same lock. + * The thread sets threadExists = false and then destroys reuseThreadMutex + * before returning, so reuseThreadMutex must not be accessed after join. */ + pthread_mutex_lock(&tempProfile->reuseThreadMutex); + bool threadStillExists = tempProfile->threadExists; + if (threadStillExists) + { + tempProfile->restartRequested = true; + pthread_cond_signal(&tempProfile->reuseThread); + } + pthread_mutex_unlock(&tempProfile->reuseThreadMutex); + + if (threadStillExists) + { + pthread_join(tempProfile->reportThread, NULL); + /* Do not access reuseThreadMutex after join: the thread destroys it + * after setting threadExists = false (see CollectAndReport cleanup). */ + } + + /* Re-acquire profileListLock for profile cleanup */ + pthread_mutex_lock(&profileListLock); + if(tempProfile->grepSeekProfile) + { + freeGrepSeekProfile(tempProfile->grepSeekProfile); + } + pthread_mutex_unlock(&profileListLock); + if(delFromDisk == true) + { + removeProfileFromDisk(REPORTPROFILES_PERSISTENCE_PATH, tempProfile->name); +#ifdef PERSIST_LOG_MON_REF + removeProfileFromDisk(SEEKFOLDER, tempProfile->name); +#endif + } + } + if(delFromDisk == true) + { + removeProfileFromDisk(REPORTPROFILES_PERSISTENCE_PATH, MSGPACK_REPORTPROFILES_PERSISTENT_FILE); + } + + pthread_mutex_lock(&profileListLock); + T2Debug("Deleting all profiles from the profileList\n"); + Vector_Destroy(profileList, freeProfile); + profileList = NULL; + Vector_Create(&profileList); + pthread_mutex_unlock(&profileListLock); + + T2Debug("%s --out\n", __FUNCTION__); + + return T2ERROR_SUCCESS; +} + +bool isProfileEnabled(const char *profileName) +{ + bool is_profile_enable = false; + Profile *get_profile = NULL; + pthread_mutex_lock(&profileListLock); + if(T2ERROR_SUCCESS != getProfile(profileName, &get_profile)) + { + T2Error("Profile : %s not found\n", profileName); + T2Debug("%s --out\n", __FUNCTION__); + pthread_mutex_unlock(&profileListLock); + return false; + } + is_profile_enable = get_profile->enable; + T2Debug("is_profile_enable = %d \n", is_profile_enable); + pthread_mutex_unlock(&profileListLock); + return is_profile_enable; +} + + +T2ERROR deleteProfile(const char *profileName) +{ + T2Debug("%s ++in\n", __FUNCTION__); + if(!initialized) + { + T2Error("profile list is not initialized yet, ignoring\n"); + return T2ERROR_FAILURE; + } + + Profile *profile = NULL; + pthread_mutex_lock(&profileListLock); + if(T2ERROR_SUCCESS != getProfile(profileName, &profile)) + { + T2Error("Profile : %s not found\n", profileName); + pthread_mutex_unlock(&profileListLock); + return T2ERROR_FAILURE; + } + + if(profile->enable) + { + profile->enable = false; + } + if(profile->isSchedulerstarted) + { + profile->isSchedulerstarted = false; + } + pthread_mutex_unlock(&profileListLock); + if(T2ERROR_SUCCESS != unregisterProfileFromScheduler(profileName)) + { + T2Info("Profile : %s already removed from scheduler\n", profileName); + } + + T2Info("Waiting for CollectAndReport to be complete : %s\n", profileName); + pthread_mutex_lock(&profileListLock); + + // Wait for any in-progress report to finish under reportInProgressMutex. + // threadExists must NOT be read here — it is written under reuseThreadMutex + // in CollectAndReport, so mixing the two mutexes causes a data race (Coverity + // LOCK_EVASION). Read threadExists separately under reuseThreadMutex below. + pthread_mutex_lock(&profile->reportInProgressMutex); + while (profile->reportInProgress) + { + pthread_cond_wait(&profile->reportInProgressCond, &profile->reportInProgressMutex); + } + pthread_mutex_unlock(&profile->reportInProgressMutex); + + /* Read threadExists under reuseThreadMutex: it is written under the same mutex + * in CollectAndReport. The thread sets threadExists = false and then destroys + * reuseThreadMutex before returning, so reuseThreadMutex must not be used after + * pthread_join returns. */ + pthread_mutex_lock(&profile->reuseThreadMutex); + bool threadStillExists = profile->threadExists; + pthread_mutex_unlock(&profile->reuseThreadMutex); + + /* Release profileListLock before pthread_join to avoid deadlock. + * pthread_join can block indefinitely if the CollectAndReport thread + * is stuck (e.g., waiting on rbusMethodMutex). Holding profileListLock during + * pthread_join prevents other threads (timeout callbacks, other profile + * operations) from making progress, creating a deadlock. + */ + pthread_mutex_unlock(&profileListLock); + + if (threadStillExists) + { + pthread_mutex_lock(&profile->reuseThreadMutex); + profile->restartRequested = true; + pthread_cond_signal(&profile->reuseThread); + pthread_mutex_unlock(&profile->reuseThreadMutex); + pthread_join(profile->reportThread, NULL); + /* Do not access reuseThreadMutex after join: the thread destroys it + * after setting threadExists = false (see CollectAndReport cleanup). */ + } + + /* Re-acquire profileListLock (wrlock) for profile cleanup operations */ + pthread_mutex_lock(&profileListLock); + + if(Vector_Size(profile->triggerConditionList) > 0) + { + rbusT2ConsumerUnReg(profile->triggerConditionList); + } + + if(profile->grepSeekProfile) + { + freeGrepSeekProfile(profile->grepSeekProfile); + } + + pthread_mutex_destroy(&profile->reportInProgressMutex); + pthread_cond_destroy(&profile->reportInProgressCond); + + T2Info("removing profile : %s from profile list\n", profile->name); +#ifdef PERSIST_LOG_MON_REF + removeProfileFromDisk(SEEKFOLDER, profile->name); +#endif + Vector_RemoveItem(profileList, profile, freeProfile); + + pthread_mutex_unlock(&profileListLock); + T2Debug("%s --out\n", __FUNCTION__); + return T2ERROR_SUCCESS; +} + +void sendLogUploadInterruptToScheduler() +{ + size_t profileIndex = 0; + Profile *tempProfile = NULL; + T2Debug("%s ++in\n", __FUNCTION__); + + pthread_mutex_lock(&profileListLock); + for(; profileIndex < Vector_Size(profileList); profileIndex++) + { + tempProfile = (Profile *)Vector_At(profileList, profileIndex); + if (Vector_Size(tempProfile->gMarkerList) > 0) + { + SendInterruptToTimeoutThread(tempProfile->name); + } + } + pthread_mutex_unlock(&profileListLock); + T2Debug("%s --out\n", __FUNCTION__); +} + +static void loadReportProfilesFromDisk(bool checkPreviousSeek) +{ + (void)checkPreviousSeek; + fetchLocalConfigs(SHORTLIVED_PROFILES_PATH, NULL); //API used for creating /tmp/t2reportprofiles dir +#if defined(FEATURE_SUPPORT_WEBCONFIG) + T2Info("loadReportProfilesFromDisk \n"); + char filePath[REPORTPROFILES_FILE_PATH_SIZE] = {'\0'}; + snprintf(filePath, sizeof(filePath), "%s%s", REPORTPROFILES_PERSISTENCE_PATH, MSGPACK_REPORTPROFILES_PERSISTENT_FILE); + /* CID: 157386 Time of check time of use (TOCTOU) */ + FILE *fp; + fp = fopen (filePath, "rb"); + if(fp != NULL) + { + T2Info("Msgpack: loadReportProfilesFromDisk \n"); + struct __msgpack__ msgpack; + fseek(fp, 0L, SEEK_END); + msgpack.msgpack_blob_size = ftell(fp); + if(msgpack.msgpack_blob_size < 0) + { + T2Error("Unable to detect the file pointer position for file %s\n", filePath); + fclose(fp); + return; + } + msgpack.msgpack_blob = malloc(sizeof(char) * msgpack.msgpack_blob_size); + if (NULL == msgpack.msgpack_blob) + { + T2Error("Unable to allocate %d bytes of memory at Line %d on %s \n", + msgpack.msgpack_blob_size, __LINE__, __FILE__); + fclose (fp); + return; + } + fseek(fp, 0L, SEEK_SET); + if(fread(msgpack.msgpack_blob, sizeof(char), msgpack.msgpack_blob_size, fp) < (size_t) msgpack.msgpack_blob_size) + { + T2Error("fread is returning fewer bytes than expected from the file %s\n", filePath); + free(msgpack.msgpack_blob); + fclose(fp); + return; + } + fclose (fp); + __ReportProfiles_ProcessReportProfilesMsgPackBlob((void *)&msgpack, checkPreviousSeek); + free(msgpack.msgpack_blob); + clearPersistenceFolder(CACHED_MESSAGE_PATH); + return; + } + T2Info("JSON: loadReportProfilesFromDisk \n"); +#endif +#if defined(PRIVACYMODES_CONTROL) + char* paramValue = NULL; + getPrivacyMode(¶mValue); + if(strcmp(paramValue, "DO_NOT_SHARE") == 0) + { + T2Warning("PrivacyModes is DO_NOT_SHARE. Reportprofiles is not supported\n"); + free(paramValue); + paramValue = NULL; + return; + } + free(paramValue); + paramValue = NULL; +#endif + + size_t configIndex = 0; + Vector *configList = NULL; + Config *config = NULL; + T2Debug("%s ++in\n", __FUNCTION__); + + Vector_Create(&configList); + fetchLocalConfigs(REPORTPROFILES_PERSISTENCE_PATH, configList); + + for(; configIndex < Vector_Size(configList); configIndex++) + { + config = Vector_At(configList, configIndex); + Profile *profile = 0; + T2Debug("Processing config with name : %s\n", config->name); + T2Debug("Config Size = %lu\n", (unsigned long)strlen(config->configData)); + + if(T2ERROR_SUCCESS == processConfiguration(&config->configData, config->name, NULL, &profile)) + { + if(T2ERROR_SUCCESS == addProfile(profile)) + { +#ifdef PERSIST_LOG_MON_REF + if(checkPreviousSeek && profile->generateNow == false && profile->triggerConditionList == NULL && profile->grepSeekProfile && loadSavedSeekConfig(profile->name, profile->grepSeekProfile) == T2ERROR_SUCCESS && firstBootStatus() ) + { + profile->checkPreviousSeek = true; + } + else + { + profile->checkPreviousSeek = false; + } +#else + profile->checkPreviousSeek = false; +#endif + T2Info("Successfully created/added new profile : %s\n", profile->name); + if(T2ERROR_SUCCESS != enableProfile(profile->name)) + { + T2Error("Failed to enable profile name : %s\n", profile->name); + } + else + { + +#ifdef PERSIST_LOG_MON_REF + if(profile->checkPreviousSeek) + { + T2Info("Previous Seek is enabled so generate the report for %s\n", profile->name); + // Trigger the report generation for the profile if previous seek is valid + NotifyTimeout(profile->name, true); + } +#endif + // Load the cached messages from previous boot, if any + populateCachedReportList(profile->name, profile->cachedReportList); + } + } + else + { + T2Error("Unable to create and add new profile for name : %s\n", config->name); + if (profile != NULL) + { + freeProfile(profile); + profile = NULL; + } + } + } + } + T2Info("Completed processing %lu profiles on the disk,trying to fetch new/updated profiles\n", (unsigned long)Vector_Size(configList)); + T2totalmem_calculate(); + Vector_Destroy(configList, freeReportProfileConfig); + clearPersistenceFolder(CACHED_MESSAGE_PATH); + + T2Debug("%s --out\n", __FUNCTION__); +} + +T2ERROR initProfileList(bool checkPreviousSeek) +{ + T2Debug("%s ++in\n", __FUNCTION__); + if(initialized) + { + T2Info("profile list is already initialized\n"); + return T2ERROR_SUCCESS; + } + initialized = true; + if(pthread_mutex_init(&profileListLock, NULL) != 0) + { + T2Error("%s rwlock init has failed\n", __FUNCTION__); + return T2ERROR_FAILURE; + } + if(pthread_mutex_init(&reportLock, NULL) != 0 ) + { + T2Error("%s mutex init has failed\n", __FUNCTION__); + pthread_mutex_destroy(&profileListLock); + initialized = false; + return T2ERROR_FAILURE; + } + + pthread_mutex_lock(&profileListLock); + Vector_Create(&profileList); + pthread_mutex_unlock(&profileListLock); + + registerConditionalReportCallBack(&triggerReportOnCondtion); + + loadReportProfilesFromDisk(checkPreviousSeek); + + T2Debug("%s --out\n", __FUNCTION__); + return T2ERROR_SUCCESS; +} + +int getProfileCount() +{ + int count = 0; + T2Debug("%s ++in\n", __FUNCTION__); + if(!initialized) + { + T2Info("profile list isn't initialized\n"); + return count; + } + pthread_mutex_lock(&profileListLock); + count = Vector_Size(profileList); + pthread_mutex_unlock(&profileListLock); + + T2Debug("%s --out\n", __FUNCTION__); + return count; +} + +hash_map_t *getProfileHashMap() +{ + size_t profileIndex = 0; + hash_map_t *profileHashMap = NULL; + Profile *tempProfile = NULL; + T2Debug("%s ++in\n", __FUNCTION__); + + pthread_mutex_lock(&profileListLock); + profileHashMap = hash_map_create(); + for(; profileIndex < Vector_Size(profileList); profileIndex++) + { + tempProfile = (Profile *)Vector_At(profileList, profileIndex); + char *profileName = strdup(tempProfile->name); + char *profileHash = strdup(tempProfile->hash); + hash_map_put(profileHashMap, profileName, profileHash, free); + } + pthread_mutex_unlock(&profileListLock); + + T2Debug("%s --out\n", __FUNCTION__); + return profileHashMap; +} + +T2ERROR uninitProfileList() +{ + T2Debug("%s ++in\n", __FUNCTION__); + + if(!initialized) + { + T2Info("profile list is not initialized yet, ignoring\n"); + return T2ERROR_SUCCESS; + } + + initialized = false; + deleteAllProfiles(false); // avoid removing multiProfiles from Disc + + if(!pthread_mutex_trylock(&triggerConditionQueMutex)) + { + if(triggerConditionQueue) + { + t2_queue_destroy(triggerConditionQueue, free); + } + + pthread_mutex_unlock(&triggerConditionQueMutex); + } + + pthread_mutex_destroy(&reportLock); + pthread_mutex_destroy(&profileListLock); + + T2Debug("%s --out\n", __FUNCTION__); + return T2ERROR_SUCCESS; +} + +T2ERROR registerTriggerConditionConsumer() +{ + + T2Debug("%s ++in\n", __FUNCTION__); +#define MAX_RETRY_COUNT 3 + size_t profileIndex = 0; + int retry_count = 0; + int retry = 0; + int timer = 16; + int ret = T2ERROR_SUCCESS; + Profile *tempProfile = NULL; + + while(retry_count <= MAX_RETRY_COUNT) + { + pthread_mutex_lock(&profileListLock); + profileIndex = 0; + for(; profileIndex < Vector_Size(profileList); profileIndex++) + { + tempProfile = (Profile *)Vector_At(profileList, profileIndex); + if(tempProfile->triggerConditionList) + { + ret = rbusT2ConsumerReg(tempProfile->triggerConditionList); + T2Debug("rbusT2ConsumerReg return = %d\n", ret); + if(ret != T2ERROR_SUCCESS) + { + retry = 1; + } + } + + } + pthread_mutex_unlock(&profileListLock); + if(retry == 1) + { + if(retry_count >= MAX_RETRY_COUNT) + { + break; + } + T2Debug("Retry Consumer Registration in %d sec\n", timer); + retry_count++; + retry = 0; + sleep(timer); + timer = timer / 2; + } + else + { + break; + } + } + T2Debug("%s --out\n", __FUNCTION__); + return ret; +} + +void NotifySchedulerstart(char* profileName, bool isschedulerstarted) +{ + size_t profileIndex = 0; + Profile *tempProfile = NULL; + pthread_mutex_lock(&profileListLock); + T2Debug("profileListLock is rdlocked %s\n", __FUNCTION__); + for(; profileIndex < Vector_Size(profileList); profileIndex++) + { + tempProfile = (Profile *)Vector_At(profileList, profileIndex); + if(tempProfile != NULL) + { + if(strncmp(tempProfile->name, profileName, strlen(profileName) + 1) == 0) + { + tempProfile->isSchedulerstarted = isschedulerstarted; + } + } + } + pthread_mutex_unlock(&profileListLock); + T2Debug("profileListLock is unlocked %s\n", __FUNCTION__); + return; +} + +T2ERROR appendTriggerCondition (Profile *tempProfile, const char *referenceName, const char *referenceValue) +{ + T2Debug("%s ++in\n", __FUNCTION__); + + T2ERROR status = T2ERROR_SUCCESS ; + + // triggerCondMutex is purposefully left unlocked from this function. + // It gets released from CollectAndReport thread once trigger condition based report is sent out. + // Reports from multiple trigger condition has to be sent mutually exclusively as separate reports. + if(!pthread_mutex_trylock(&tempProfile->triggerCondMutex)) + { + T2Debug("%s : Lock acquisition succeeded for tempProfile->triggerCondMutex\n ", __FUNCTION__); + cJSON *temparrayItem = cJSON_CreateObject(); + cJSON_AddStringToObject(temparrayItem, "reference", referenceName); + cJSON_AddStringToObject(temparrayItem, "value", referenceValue); + cJSON *temparrayItem1 = cJSON_CreateObject(); + + cJSON_AddItemToObject(temparrayItem1, "TriggerConditionResult", temparrayItem); + tempProfile->jsonReportObj = temparrayItem1; + //pthread_mutex_unlock(&tempProfile->triggerCondMutex); + + } + else + { + T2Warning("%s : Failed to get a lock on tempProfile->triggerCondMutex for condition %s \n ", __FUNCTION__, referenceName); + status = T2ERROR_FAILURE; + // Push this trigger condition to a que. + // Implement a callback function to trigger report generation for referenceName & value + + if(!pthread_mutex_trylock(&triggerConditionQueMutex)) + { + T2Debug("%s : Lock on triggerConditionQueMutex\n", __FUNCTION__); + if(NULL == triggerConditionQueue) + { + triggerConditionQueue = t2_queue_create(); + if(!triggerConditionQueue) + { + T2Error("Failed to create triggerConditionQueue, not proceeding further\n"); + T2Debug("%s : Unlock on triggerConditionQueMutex\n", __FUNCTION__); + pthread_mutex_unlock(&triggerConditionQueMutex); + T2Debug("%s --out\n", __FUNCTION__); + return status ; + } + T2Debug("%s : Que for storing the trigger conditions is created \n", __FUNCTION__); + } + triggerConditionObj *triggerCond = (triggerConditionObj*) malloc(sizeof(triggerConditionObj)); + if(triggerCond) + { + if(NULL != referenceName && NULL != referenceValue) + { + T2Info("%s : Push referenceName = %s & referenceValue = %s to que \n ", __FUNCTION__, referenceName, referenceValue); + memset(triggerCond, 0, sizeof(triggerConditionObj)); + strncpy(triggerCond->referenceName, referenceName, (MAX_LEN - 1)); + strncpy(triggerCond->referenceValue, referenceValue, (MAX_LEN - 1)); + t2_queue_push(triggerConditionQueue, (void*) triggerCond); + // Ownership of triggerCond is transferred to triggerConditionQueue and will be freed after being popped. + } + else + { + T2Warning("%s : referenceName or referenceValue is published as null, ignoring trigger condition \n ", __FUNCTION__); + } + + } + else + { + T2Error("Failed to allocate memory for triggerConditionObj\n"); + } + + T2Debug("%s : Unlock on triggerConditionQueMutex\n", __FUNCTION__); + pthread_mutex_unlock(&triggerConditionQueMutex); + + /* ref RDKB-55438 Commenting following code as this is causing crash, we can't free triggerCond here as this + has been added to the queue, this is freed in the reportGenerationCompleteReceiver function after queue pop + + if(triggerCond != NULL) { + free(triggerCond);//CID 335291: Resource leak (RESOURCE_LEAK) + } + */ + + } + else + { + T2Warning("%s : Failed to get a lock on triggerConditionQueMutex for condition %s \n ", __FUNCTION__, referenceName); + + } + } + + T2Debug("%s --out\n", __FUNCTION__); + return status; +} + +void reportGenerationCompleteReceiver(char *profileName) +{ + + T2Debug("%s ++in\n", __FUNCTION__); + T2Info("%s called with argument %s\n", __FUNCTION__, profileName); + + if(!pthread_mutex_lock(&triggerConditionQueMutex)) + { + if(NULL != triggerConditionQueue) + { + T2Info("%s : %d report generating triggers pending in que \n ", __FUNCTION__, t2_queue_count(triggerConditionQueue)); + if(t2_queue_count(triggerConditionQueue) > 0) + { + triggerConditionObj *triggerCond = (triggerConditionObj*) t2_queue_pop(triggerConditionQueue); + if(triggerCond) + { + // Que has to be unlocked before generating a trigger condition + pthread_mutex_unlock(&triggerConditionQueMutex); + triggerReportOnCondtion(triggerCond->referenceName, triggerCond->referenceValue); + free(triggerCond); + triggerCond = NULL; + } + else + { + T2Debug("%s : Trigger condition is null \n", __FUNCTION__); + pthread_mutex_unlock(&triggerConditionQueMutex); + } + } + else + { + T2Debug("%s : Unlock on triggerConditionQueMutex\n", __FUNCTION__); + pthread_mutex_unlock(&triggerConditionQueMutex); + T2Debug("No more report on condition events present in que \n"); + } + } + else + { + pthread_mutex_unlock(&triggerConditionQueMutex); + } + } + else + { + T2Error("Failed to get lock on triggerConditionQueMutex \n"); + } + + T2Debug("%s --out\n", __FUNCTION__); +} + +T2ERROR triggerReportOnCondtion(const char *referenceName, const char *referenceValue) +{ + T2Debug("%s ++in\n", __FUNCTION__); + + T2Debug("referenceName = %s referenceValue = %s \n", referenceName, referenceValue); + + size_t j, profileIndex = 0; + Profile *tempProfile = NULL; + + pthread_mutex_lock(&profileListLock); + for(; profileIndex < Vector_Size(profileList); profileIndex++) + { + tempProfile = (Profile *)Vector_At(profileList, profileIndex); + if(tempProfile->triggerConditionList && (tempProfile->triggerConditionList->count > 0)) + { + for( j = 0; j < tempProfile->triggerConditionList->count; j++ ) + { + TriggerCondition *triggerCondition = ((TriggerCondition *) Vector_At(tempProfile->triggerConditionList, j)); + if(strcmp(triggerCondition->reference, referenceName) == 0) + { + if(triggerCondition->report) + { + if ( T2ERROR_SUCCESS == appendTriggerCondition(tempProfile, referenceName, referenceValue)) + { + tempProfile->triggerReportOnCondition = true; + tempProfile->minThresholdDuration = triggerCondition->minThresholdDuration; + T2Debug("%s : Assign callback function as reportGenerationCompleteReceiver \n", __FUNCTION__); + tempProfile->callBackOnReportGenerationComplete = reportGenerationCompleteReceiver; + + char *tempProfilename = strdup(tempProfile->name); //RDKB-42640 + + // profileListLock should be unlocked before sending interrupt for report generation + T2Debug("%s : Release lock on &profileListLock\n ", __FUNCTION__); + pthread_mutex_unlock(&profileListLock); + T2Info("Triggering report on condition for %s with %s operator, %d threshold\n", triggerCondition->reference, + triggerCondition->oprator, triggerCondition->threshold); + if(tempProfile->isSchedulerstarted) + { + SendInterruptToTimeoutThread(tempProfilename); + // triggerCondMutex will be unlocked by CollectAndReport after report generation + } + else + { + T2Info("For Profile %s scheduler is not enabled yet so triggering the condition is ignored now\n", tempProfilename); + tempProfile->triggerReportOnCondition = false; + pthread_mutex_unlock(&tempProfile->triggerCondMutex); + + } + free(tempProfilename); //RDKB-42640 + return T2ERROR_SUCCESS ; + } + else + { + T2Info("Report generation will take place by popping up from the que by callback function \n"); + T2Debug("%s : Release lock on &profileListLock\n ", __FUNCTION__); + pthread_mutex_unlock(&profileListLock); + return T2ERROR_SUCCESS; + } + } + } + } + } + } + pthread_mutex_unlock(&profileListLock); + T2Debug("%s --out\n", __FUNCTION__); + return T2ERROR_SUCCESS; +} + +unsigned int getMinThresholdDuration(char *profileName) +{ + unsigned int minThresholdDuration = 0; + Profile *get_profile = NULL; + T2Debug("%s --in\n", __FUNCTION__); + pthread_mutex_lock(&profileListLock); + if(T2ERROR_SUCCESS != getProfile(profileName, &get_profile)) + { + T2Error("Profile : %s not found\n", profileName); + T2Debug("%s --out\n", __FUNCTION__); + pthread_mutex_unlock(&profileListLock); + return 0; + } + minThresholdDuration = get_profile->minThresholdDuration; + get_profile->minThresholdDuration = 0; // reinit the value + T2Debug("minThresholdDuration = %u \n", minThresholdDuration); + pthread_mutex_unlock(&profileListLock); + T2Debug("%s --out\n", __FUNCTION__); + return minThresholdDuration; +} + -/** - * Lock Hierarchy (acquire in ascending order to prevent deadlocks): - * L0: profileListLock (module-level rwlock - protects profileList) - * L1: reuseThreadMutex (per-profile - protects thread lifecycle) - * L2: reportInProgressMutex (per-profile - protects reportInProgress flag) - * L3: triggerCondMutex / eventMutex / reportMutex (per-profile - leaf locks) - * - * Rules: - * - Always acquire L0 before L1, L1 before L2, etc. - * - Never hold a higher-numbered lock when acquiring a lower-numbered lock. - * - profileListLock uses rdlock for lookups/iterations, wrlock for add/remove. - * - Release profileListLock before long operations (pthread_join, HTTP send). - */ -typedef struct _Profile -{ - bool enable; - bool isSchedulerstarted; - bool isUpdated; - bool reportInProgress; - pthread_cond_t reportInProgressCond; - pthread_mutex_t reportInProgressMutex; - bool generateNow; - bool deleteonTimeout; - bool bClearSeekMap; - bool checkPreviousSeek; // To support Previous_Logs report post reboot - bool saveSeekConfig; // To save the Seek config to persistant storage - bool triggerReportOnCondition; - bool trim; - void (*callBackOnReportGenerationComplete)(char*); - char* hash; - char* name; - char* protocol; - char* encodingType; - char* Description; - char* version; - char* RootName; - char* timeRef; - JSONEncoding *jsonEncoding; - bool reportOnUpdate; - unsigned int firstReportingInterval; - unsigned int SendErr; - unsigned int reportingInterval; - unsigned int activationTimeoutPeriod; - unsigned int maxUploadLatency; - unsigned int paramNumOfEntries; - unsigned int minThresholdDuration; - Vector *paramList; - Vector *staticParamList; - T2HTTP *t2HTTPDest; - T2RBUS *t2RBUSDest; - Vector *eMarkerList; - Vector *gMarkerList; - Vector *topMarkerList; - Vector *cachedReportList; - cJSON *jsonReportObj; - pthread_t reportThread; - pthread_mutex_t triggerCondMutex; - pthread_mutex_t eventMutex; - pthread_mutex_t reportMutex; - pthread_cond_t reportcond; - struct timespec currentTime; - struct timespec maxlatencyTime; - Vector *triggerConditionList; - pthread_cond_t reuseThread; - pthread_mutex_t reuseThreadMutex; - bool restartRequested; - bool threadExists; - GrepSeekProfile *grepSeekProfile; // To store GrepConfig -} Profile; - -T2ERROR initProfileList(bool checkPreviousSeek); - -T2ERROR uninitProfileList(); - -T2ERROR addProfile(Profile *profile); - -int getProfileCount(); - -T2ERROR profileWithNameExists(const char *profileName, bool *bProfileExists); - -T2ERROR Profile_storeMarkerEvent(const char *profileName, T2Event *eventInfo); - -T2ERROR enableProfile(const char *profileName); - -T2ERROR disableProfile(const char *profileName, bool *isDeleteRequired); - -T2ERROR deleteProfile(const char *profileName); - -T2ERROR deleteAllProfiles(bool delFromDisk); - -void updateMarkerComponentMap(); - -hash_map_t *getProfileHashMap(); - -void sendLogUploadInterruptToScheduler(); - -void NotifyTimeout(const char* profileName, bool isClearSeekMap); - -void getMarkerCompRbusSub(bool subscription); - -bool isProfileEnabled(const char *profileName); - -T2ERROR registerTriggerConditionConsumer(); - -T2ERROR triggerReportOnCondtion(const char *referenceName, const char *referenceValue); - -unsigned int getMinThresholdDuration(char *profileName); - -void reportGenerationCompleteReceiver(char* profileName); - -void NotifySchedulerstart(char* profileName, bool isschedulerstarted); - -T2ERROR appendTriggerCondition (Profile *tempProfile, const char *referenceName, const char *referenceValue); - -T2ERROR ReportProfiles_addReportProfile(Profile *profile); -T2ERROR RemovePreRPfromDisk(const char* path, hash_map_t *map); -#endif /* _PROFILE_H_ */