static void dbCaTask(void *arg) { taskwdInsert(0, NULL, NULL); SEVCHK(ca_context_create(ca_enable_preemptive_callback), "dbCaTask calling ca_context_create"); dbCaClientContext = ca_current_context (); SEVCHK(ca_add_exception_event(exceptionCallback,NULL), "ca_add_exception_event"); epicsEventSignal(startStopEvent); /* channel access event loop */ while (TRUE){ do { epicsEventMustWait(workListEvent); } while (dbCaCtl == ctlPause); while (TRUE) { /* process all requests in workList*/ caLink *pca; short link_action; int status; epicsMutexMustLock(workListLock); if (!(pca = (caLink *)ellGet(&workList))){ /* Take off list head */ epicsMutexUnlock(workListLock); if (dbCaCtl == ctlExit) goto shutdown; break; /* workList is empty */ } link_action = pca->link_action; pca->link_action = 0; if (link_action & CA_CLEAR_CHANNEL) --removesOutstanding; epicsMutexUnlock(workListLock); /* Give back immediately */ if (link_action & CA_CLEAR_CHANNEL) { /* This must be first */ dbCaLinkFree(pca); /* No alarm is raised. Since link is changing so what? */ continue; /* No other link_action makes sense */ } if (link_action & CA_CONNECT) { status = ca_create_channel( pca->pvname,connectionCallback,(void *)pca, CA_PRIORITY_DB_LINKS, &(pca->chid)); if (status != ECA_NORMAL) { errlogPrintf("dbCaTask ca_create_channel %s\n", ca_message(status)); printLinks(pca); continue; } dbca_chan_count++; status = ca_replace_access_rights_event(pca->chid, accessRightsCallback); if (status != ECA_NORMAL) { errlogPrintf("dbCaTask replace_access_rights_event %s\n", ca_message(status)); printLinks(pca); } continue; /*Other options must wait until connect*/ } if (ca_state(pca->chid) != cs_conn) continue; if (link_action & CA_WRITE_NATIVE) { assert(pca->pputNative); if (pca->putType == CA_PUT) { status = ca_array_put( pca->dbrType, pca->nelements, pca->chid, pca->pputNative); } else if (pca->putType==CA_PUT_CALLBACK) { status = ca_array_put_callback( pca->dbrType, pca->nelements, pca->chid, pca->pputNative, putCallback, pca); } else { status = ECA_PUTFAIL; } if (status != ECA_NORMAL) { errlogPrintf("dbCaTask ca_array_put %s\n", ca_message(status)); printLinks(pca); } epicsMutexMustLock(pca->lock); if (status == ECA_NORMAL) pca->newOutNative = FALSE; epicsMutexUnlock(pca->lock); } if (link_action & CA_WRITE_STRING) { assert(pca->pputString); if (pca->putType == CA_PUT) { status = ca_array_put( DBR_STRING, 1, pca->chid, pca->pputString); } else if (pca->putType==CA_PUT_CALLBACK) { status = ca_array_put_callback( DBR_STRING, 1, pca->chid, pca->pputString, putCallback, pca); } else { status = ECA_PUTFAIL; } if (status != ECA_NORMAL) { errlogPrintf("dbCaTask ca_array_put %s\n", ca_message(status)); printLinks(pca); } epicsMutexMustLock(pca->lock); if (status == ECA_NORMAL) pca->newOutString = FALSE; epicsMutexUnlock(pca->lock); } /*CA_GET_ATTRIBUTES before CA_MONITOR so that attributes available * before the first monitor callback */ if (link_action & CA_GET_ATTRIBUTES) { status = ca_get_callback(DBR_CTRL_DOUBLE, pca->chid, getAttribEventCallback, pca); if (status != ECA_NORMAL) { errlogPrintf("dbCaTask ca_get_callback %s\n", ca_message(status)); printLinks(pca); } } if (link_action & CA_MONITOR_NATIVE) { size_t element_size; element_size = dbr_value_size[ca_field_type(pca->chid)]; epicsMutexMustLock(pca->lock); pca->pgetNative = dbCalloc(pca->nelements, element_size); epicsMutexUnlock(pca->lock); status = ca_add_array_event( ca_field_type(pca->chid)+DBR_TIME_STRING, ca_element_count(pca->chid), pca->chid, eventCallback, pca, 0.0, 0.0, 0.0, 0); if (status != ECA_NORMAL) { errlogPrintf("dbCaTask ca_add_array_event %s\n", ca_message(status)); printLinks(pca); } } if (link_action & CA_MONITOR_STRING) { epicsMutexMustLock(pca->lock); pca->pgetString = dbCalloc(1, MAX_STRING_SIZE); epicsMutexUnlock(pca->lock); status = ca_add_array_event(DBR_TIME_STRING, 1, pca->chid, eventCallback, pca, 0.0, 0.0, 0.0, 0); if (status != ECA_NORMAL) { errlogPrintf("dbCaTask ca_add_array_event %s\n", ca_message(status)); printLinks(pca); } } } SEVCHK(ca_flush_io(), "dbCaTask"); } shutdown: taskwdRemove(0); if (dbca_chan_count == 0) ca_context_destroy(); else fprintf(stderr, "dbCa: chan_count = %d at shutdown\n", dbca_chan_count); epicsEventSignal(startStopEvent); }
void popupPvInfo(DisplayInfo *displayInfo) { DlElement *pE; Record **records; chid chId; int i, status; Record *pR; Channel *pCh; char descName[MAX_TOKEN_LENGTH]; char *pDot; double connTimeout; #if DEBUG_PVINFO XUngrabPointer(display,CurrentTime); #endif /* Check if another call is in progress */ if(pvInfo) { medmPostMsg(1,"popupPvInfo: " "Another PV Info request is already in progress\n" " It is probably having problems\n" " Wait for it to finish\n"); return; } /* Create the dialog box if it has not been created */ if(!pvInfoS) createPvInfoDlg(); /* Get the records */ records = getPvInfoFromDisplay(displayInfo, &nPvInfoPvs, &pE); if(!records) return; pvInfoElement = pE; /* Allocate space */ pvInfo = (PvInfo *)calloc(nPvInfoPvs, sizeof(PvInfo)); if(!pvInfo) { medmPostMsg(1,"popupPvInfo: Memory allocation error\n"); if(records) free(records); if(pvInfoS && XtIsManaged(pvInfoS)) return; } /* Loop over the records, initialize, and initiate search for DESC */ for(i=0; i < nPvInfoPvs; i++) { /* Initialize */ pvInfo[i].pvChid = NULL; pvInfo[i].pvOk = False; pvInfo[i].timeOk = False; pvInfo[i].descChid = NULL; pvInfo[i].descOk = False; strcpy(pvInfo[i].descVal, NOT_AVAILABLE); #if defined(DBR_CLASS_NAME) && DO_RTYP pvInfo[i].rtypOk = False; strcpy(pvInfo[i].rtypVal, NOT_AVAILABLE); #endif /* Check for a valid record */ if(records[i]) { pR = pvInfo[i].record = records[i]; pCh = getChannelFromRecord(pR); if(!pCh) continue; if(!pCh->chid) continue; chId = pvInfo[i].pvChid = pCh->chid; } else continue; pvInfo[i].pvOk = True; /* Don't try the others unless the PV is connected */ if(ca_state(chId) != cs_conn || !ca_read_access(chId)) continue; /* Construct the DESC name */ strcpy(descName,ca_name(chId)); pDot = strchr(descName,'.'); if(pDot) { /* Assume it is a name with a field and replace the field * with DESC */ strcpy(pDot,".DESC"); } else { /* Append .DESC */ strcat(descName,".DESC"); } /* Search for the DESC */ status = ca_search(descName, &pvInfo[i].descChid); if(status == ECA_NORMAL) { pvInfo[i].descOk = True; } else { medmPostMsg(1,"popupPvInfo: DESC: ca_search for %s: %s\n", descName, ca_message(status)); } } /* Free the records, they are now stored in pvInfo */ if(records) free(records); /* Wait for the searches (Timeouts should be uncommon) */ status=ca_pend_io(CA_PEND_IO_TIME); if(status != ECA_NORMAL) { medmPostMsg(1,"popupPvInfo: Waited %g seconds. " "Did not find the DESC information (%s).\n", CA_PEND_IO_TIME, descName); } /* Loop over the records and do the gets */ nPvInfoCbs = 0; for(i=0; i < nPvInfoPvs; i++) { if(!pvInfo[i].pvOk) continue; /* Don't try the others unless the PV is connected */ chId = pvInfo[i].pvChid; if(ca_state(chId) != cs_conn || !ca_read_access(chId)) continue; /* Get the DESC */ if(ca_state(pvInfo[i].descChid) == cs_conn && ca_read_access(pvInfo[i].descChid)) { /* Do the get */ status = ca_get_callback(DBR_STRING, pvInfo[i].descChid, pvInfoDescGetCb, &pvInfo[i]); if(status == ECA_NORMAL) { nPvInfoCbs++; } else { pvInfo[i].descOk = False; medmPostMsg(1,"pvInfoConnectCb: DESC: ca_array_get_callback" " for %s: %s\n", ca_name(pvInfo[i].descChid), ca_message(status)); } } else { pvInfo[i].descOk = False; } /* Get the time value as a string */ status = ca_get_callback(DBR_TIME_STRING, chId, pvInfoTimeGetCb, &pvInfo[i]); if(status == ECA_NORMAL) { nPvInfoCbs++; } else { medmPostMsg(1,"popupPvInfo: STAMP: ca_get_callback for %s: %s\n", ca_name(chId), ca_message(status)); } #if defined(DBR_CLASS_NAME) && DO_RTYP /* Get the RTYP */ status = ca_get_callback(DBR_CLASS_NAME, chId, pvInfoRtypGetCb, &pvInfo[i]); if(status == ECA_NORMAL) { nPvInfoCbs++; } else { medmPostMsg(1,"popupPvInfo: RTYP: ca_get_callback for %s: %s\n", ca_name(chId), ca_message(status)); } #endif } /* Add a timeout and poll if there are callbacks * The timeout is a safety net and should never be called * All callbacks should come back inside the EPICS_CA_CONN_TMO * Wait for 2 times this */ if(nPvInfoCbs) { ca_poll(); /* May not be really necessary here */ status = envGetDoubleConfigParam(&EPICS_CA_CONN_TMO, &connTimeout); if (status == 0) pvInfoTime = (unsigned long)(2000.*connTimeout+.5); else pvInfoTime = PVINFO_TIMEOUT; pvInfoTimeoutId = XtAppAddTimeOut(appContext, pvInfoTime, pvInfoTimeout, NULL); pvInfoTimerOn = True; } else { pvInfoWriteInfo(); } #if DEBUG_PVINFO print("popupPvInfo: nPvInfoCbs=%d timeout=%ld\n", nPvInfoCbs, nPvInfoCbs?pvInfoTime:0L); #endif }