Пример #1
0
static long dbPutFieldLink(DBADDR *paddr,
    short dbrType, const void *pbuffer, long nRequest)
{
    dbLinkInfo  link_info;
    DBADDR      *pdbaddr = NULL;
    dbCommon    *precord = paddr->precord;
    dbCommon    *lockrecs[2];
    dbLocker    locker;
    dbFldDes    *pfldDes = paddr->pfldDes;
    long        special = paddr->special;
    struct link *plink = (struct link *)paddr->pfield;
    const char  *pstring = (const char *)pbuffer;
    struct dsxt *old_dsxt = NULL;
    struct dset *new_dset = NULL;
    struct dsxt *new_dsxt = NULL;
    devSup      *new_devsup = NULL;
    long        status;
    int         isDevLink;
    short       scan;

    STATIC_ASSERT(DBLOCKER_NALLOC>=2);

    switch (dbrType) {
    case DBR_CHAR:
    case DBR_UCHAR:
        if (pstring[nRequest - 1] != '\0')
            return S_db_badDbrtype;
        break;

    case DBR_STRING:
        break;

    default:
        return S_db_badDbrtype;
    }

    status = dbParseLink(pstring, pfldDes->field_type, &link_info);
    if (status)
        return status;

    if (link_info.ltype == PV_LINK &&
        (link_info.modifiers & (pvlOptCA | pvlOptCP | pvlOptCPP)) == 0) {
        DBADDR tempaddr;

        if (dbNameToAddr(link_info.target, &tempaddr)==0) {
            /* This will become a DB link. */
            pdbaddr = malloc(sizeof(*pdbaddr));
            if (!pdbaddr) {
                status = S_db_noMemory;
                goto cleanup;
            }
            *pdbaddr = tempaddr; /* struct copy */
        }
    }

    isDevLink = ellCount(&precord->rdes->devList) > 0 &&
                pfldDes->isDevLink;

    memset(&locker, 0, sizeof(locker));
    lockrecs[0] = precord;
    lockrecs[1] = pdbaddr ? pdbaddr->precord : NULL;
    dbLockerPrepare(&locker, lockrecs, 2);

    dbScanLockMany(&locker);

    scan = precord->scan;

    if (isDevLink) {
        new_devsup = dbDTYPtoDevSup(precord->rdes, precord->dtyp);
        if (new_devsup) {
            new_dset = new_devsup->pdset;
            new_dsxt = new_devsup->pdsxt;
        }
    }

    if (dbCanSetLink(plink, &link_info, new_devsup)) {
        /* link type mis-match prevents assignment */
        status = S_dbLib_badField;
        goto unlock;
    }

    if (isDevLink) {
        if (precord->dset) {
            devSup *old_devsup = dbDSETtoDevSup(precord->rdes, precord->dset);

            if (old_devsup)
                old_dsxt = old_devsup->pdsxt;
        }

        if (new_dsxt == NULL ||
            new_dsxt->add_record == NULL ||
            (precord->dset && old_dsxt == NULL) ||
            (old_dsxt && old_dsxt->del_record == NULL)) {
            status = S_db_noSupport;
            goto unlock;
        }

        if (scan == menuScanI_O_Intr) {
            scanDelete(precord);
            precord->scan = menuScanPassive;
        }

        if (old_dsxt) {
            status = old_dsxt->del_record(precord);
            if (status)
                goto restoreScan;
        }
    }

    switch (plink->type) { /* Old link type */
    case DB_LINK:
    case CA_LINK:
    case CONSTANT:
        dbRemoveLink(&locker, plink);   /* link type becomes PV_LINK */
        break;

    case PV_LINK:
    case MACRO_LINK:
        break;  /* should never get here */

    default: /* Hardware address */
        if (!isDevLink) {
            status = S_db_badHWaddr;
            goto restoreScan;
        }
        break;
    }

    if (special) status = dbPutSpecial(paddr, 0);

    if (!status) status = dbSetLink(plink, &link_info, new_devsup);

    if (!status && special) status = dbPutSpecial(paddr, 1);

    if (status) {
        if (isDevLink) {
            precord->dset = NULL;
            precord->pact = TRUE;
        }
        goto postScanEvent;
    }

    if (isDevLink) {
        precord->dpvt = NULL;
        precord->dset = new_dset;
        precord->pact = FALSE;

        status = new_dsxt->add_record(precord);
        if (status) {
            precord->dset = NULL;
            precord->pact = TRUE;
            goto postScanEvent;
        }
    }

    switch (plink->type) { /* New link type */
    case PV_LINK:
    case CONSTANT:
        dbAddLink(&locker, plink, pfldDes->field_type, pdbaddr);
        break;

    case DB_LINK:
    case CA_LINK:
    case MACRO_LINK:
        break;  /* should never get here */

    default: /* Hardware address */
        if (!isDevLink) {
            status = S_db_badHWaddr;
            goto postScanEvent;
        }
        break;
    }
    db_post_events(precord, plink, DBE_VALUE | DBE_LOG);

restoreScan:
    if (isDevLink &&
        scan == menuScanI_O_Intr) { /* undo scanDelete() */
        precord->scan = scan;
        scanAdd(precord);
    }
postScanEvent:
    if (scan != precord->scan)
        db_post_events(precord, &precord->scan, DBE_VALUE | DBE_LOG);
unlock:
    dbScanUnlockMany(&locker);
    dbLockerFinalize(&locker);
cleanup:
    free(link_info.target);
    return status;
}
Пример #2
0
long epicsShareAPI dbPut(DBADDR *paddr, short dbrType,
    const void *pbuffer, long nRequest)
{
    dbCommon *precord = paddr->precord;
    short field_type  = paddr->field_type;
    long no_elements  = paddr->no_elements;
    long special      = paddr->special;
    long offset;
    long status = 0;
    dbFldDes *pfldDes;
    int isValueField;

    if (special == SPC_ATTRIBUTE) return S_db_noMod;

    if (dbrType == DBR_PUT_ACKT && field_type <= DBF_DEVICE) {
        return putAckt(paddr, (unsigned short *)pbuffer, 1, 1, 0);
    } else if (dbrType == DBR_PUT_ACKS && field_type <= DBF_DEVICE) {
        return putAcks(paddr, (unsigned short *)pbuffer, 1, 1, 0);
    } else if (INVALID_DB_REQ(dbrType) || field_type > DBF_DEVICE) {
        char message[80];

        sprintf(message, "dbPut: Request type is %d", dbrType);
        recGblDbaddrError(S_db_badDbrtype, paddr, message);
        return S_db_badDbrtype;
    }

    if (special) {
        status = dbPutSpecial(paddr, 0);
        if (status) return status;
    }

    if (no_elements <= 1) {
        status = dbFastPutConvertRoutine[dbrType][field_type](pbuffer,
            paddr->pfield, paddr);
    } else {
        struct rset *prset = dbGetRset(paddr);

        if (paddr->special == SPC_DBADDR &&
            prset && prset->get_array_info) {
            long dummy;

            status = prset->get_array_info(paddr, &dummy, &offset);
        }
        else
            offset = 0;
        if (no_elements < nRequest) nRequest = no_elements;
        if (!status)
            status = dbPutConvertRoutine[dbrType][field_type](paddr, pbuffer,
                nRequest, no_elements, offset);

        /* update array info */
        if (!status &&
            paddr->special == SPC_DBADDR &&
            prset && prset->put_array_info) {
            status = prset->put_array_info(paddr, nRequest);
        }
    }
    if (status) return status;

    /* check if special processing is required */
    if (special) {
        status = dbPutSpecial(paddr,1);
        if (status) return status;
    }

    /* Propagate monitor events for this field, */
    /* unless the field field is VAL and PP is true. */
    pfldDes = paddr->pfldDes;
    isValueField = dbIsValueField(pfldDes);
    if (isValueField) precord->udf = FALSE;
    if (precord->mlis.count &&
        !(isValueField && pfldDes->process_passive))
        db_post_events(precord, paddr->pfield, DBE_VALUE | DBE_LOG);

    return status;
}
Пример #3
0
long dbPut(DBADDR *paddr, short dbrType,
    const void *pbuffer, long nRequest)
{
    dbCommon *precord = paddr->precord;
    short field_type  = paddr->field_type;
    long no_elements  = paddr->no_elements;
    long special      = paddr->special;
    void *pfieldsave  = paddr->pfield;
    struct rset *prset = dbGetRset(paddr);
    long status = 0;
    long offset;
    dbFldDes *pfldDes;
    int isValueField;

    if (special == SPC_ATTRIBUTE)
        return S_db_noMod;

    if (dbrType == DBR_PUT_ACKT && field_type <= DBF_DEVICE) {
        return putAckt(paddr, pbuffer, 1, 1, 0);
    } else if (dbrType == DBR_PUT_ACKS && field_type <= DBF_DEVICE) {
        return putAcks(paddr, pbuffer, 1, 1, 0);
    } else if (INVALID_DB_REQ(dbrType) || field_type > DBF_DEVICE) {
        char message[80];

        sprintf(message, "dbPut: Request type is %d", dbrType);
        recGblDbaddrError(S_db_badDbrtype, paddr, message);
        return S_db_badDbrtype;
    }

    if (special) {
        status = dbPutSpecial(paddr, 0);
        if (status) return status;
    }

    if (paddr->pfldDes->special == SPC_DBADDR &&
        prset && prset->get_array_info) {
        long dummy;

        status = prset->get_array_info(paddr, &dummy, &offset);
        /* paddr->pfield may be modified */
        if (status) goto done;
    } else
        offset = 0;

    if (no_elements <= 1) {
        status = dbFastPutConvertRoutine[dbrType][field_type](pbuffer,
            paddr->pfield, paddr);
        nRequest = 1;
    } else {
        if (no_elements < nRequest)
            nRequest = no_elements;
        status = dbPutConvertRoutine[dbrType][field_type](paddr, pbuffer,
            nRequest, no_elements, offset);
    }

    /* update array info */
    if (!status &&
        paddr->pfldDes->special == SPC_DBADDR &&
        prset && prset->put_array_info) {
        status = prset->put_array_info(paddr, nRequest);
    }

    /* Always do special processing if needed */
    if (special) {
        long status2 = dbPutSpecial(paddr, 1);
        if (status2) goto done;
    }
    if (status) goto done;

    /* Propagate monitor events for this field, */
    /* unless the field is VAL and PP is true. */
    pfldDes = paddr->pfldDes;
    isValueField = dbIsValueField(pfldDes);
    if (isValueField) precord->udf = FALSE;
    if (precord->mlis.count &&
        !(isValueField && pfldDes->process_passive))
        db_post_events(precord, pfieldsave, DBE_VALUE | DBE_LOG);
    /* If this field is a property (metadata) field,
     * then post a property change event (even if the field
     * didn't change).
     */
    if (precord->mlis.count && pfldDes->prop)
        db_post_events(precord, NULL, DBE_PROPERTY);
done:
    paddr->pfield = pfieldsave;
    return status;
}
Пример #4
0
static long dbPutFieldLink(DBADDR *paddr,
    short dbrType, const void *pbuffer, long nRequest)
{
    dbCommon    *precord = paddr->precord;
    dbFldDes    *pfldDes = paddr->pfldDes;
    long        special = paddr->special;
    DBLINK      *plink = (DBLINK *)paddr->pfield;
    const char  *pstring = (const char *)pbuffer;
    DBENTRY     dbEntry;
    DBADDR      dbaddr;
    struct dsxt *old_dsxt = NULL;
    struct dset *new_dset = NULL;
    struct dsxt *new_dsxt = NULL;
    long        status;
    int         isDevLink;
    short       scan;

    switch (dbrType) {
    case DBR_CHAR:
    case DBR_UCHAR:
        if (pstring[nRequest - 1] != '\0')
            return S_db_badDbrtype;
        break;

    case DBR_STRING:
        break;

    default:
        return S_db_badDbrtype;
    }

    dbInitEntry(pdbbase, &dbEntry);
    status = dbFindRecord(&dbEntry, precord->name);
    if (!status) status = dbFindField(&dbEntry, pfldDes->name);
    if (status) goto finish;

    isDevLink = ellCount(&precord->rdes->devList) > 0 &&
                (strcmp(pfldDes->name, "INP") == 0 ||
                 strcmp(pfldDes->name, "OUT") == 0);

    dbLockSetGblLock();
    dbLockSetRecordLock(precord);

    scan = precord->scan;

    if (isDevLink) {
        devSup *pdevSup = dbDTYPtoDevSup(precord->rdes, precord->dtyp);
        if (pdevSup) {
            new_dset = pdevSup->pdset;
            new_dsxt = pdevSup->pdsxt;
        }

        if (precord->dset) {
            pdevSup = dbDSETtoDevSup(precord->rdes, precord->dset);
            if (pdevSup)
                old_dsxt = pdevSup->pdsxt;
        }

        if (new_dsxt == NULL ||
            new_dsxt->add_record == NULL ||
            (precord->dset && old_dsxt == NULL) ||
            (old_dsxt && old_dsxt->del_record == NULL)) {
            status = S_db_noSupport;
            goto unlock;
        }

        if (scan == menuScanI_O_Intr) {
            scanDelete(precord);
            precord->scan = menuScanPassive;
        }

        if (old_dsxt) {
            status = old_dsxt->del_record(precord);
            if (status)
                goto restoreScan;
        }
    }

    switch (plink->type) { /* Old link type */
    case DB_LINK:
        free(plink->value.pv_link.pvt);
        plink->value.pv_link.pvt = 0;
        plink->type = PV_LINK;
        plink->value.pv_link.getCvt = 0;
        plink->value.pv_link.pvlMask = 0;
        plink->value.pv_link.lastGetdbrType = 0;
        dbLockSetSplit(precord);
        break;

    case CA_LINK:
        dbCaRemoveLink(plink);
        plink->type = PV_LINK;
        plink->value.pv_link.getCvt = 0;
        plink->value.pv_link.pvlMask = 0;
        plink->value.pv_link.lastGetdbrType = 0;
        break;

    case CONSTANT:
        break;  /* do nothing */

    case PV_LINK:
    case MACRO_LINK:
        break;  /* should never get here */

    default: /* Hardware address */
        if (!isDevLink) {
            status = S_db_badHWaddr;
            goto restoreScan;
        }
        break;
    }

    if (special) status = dbPutSpecial(paddr, 0);

    if (!status) status = dbPutString(&dbEntry, pstring);

    if (!status && special) status = dbPutSpecial(paddr, 1);

    if (status) {
        if (isDevLink) {
            precord->dset = NULL;
            precord->pact = TRUE;
        }
        goto postScanEvent;
    }

    if (isDevLink) {
        precord->dpvt = NULL;
        precord->dset = new_dset;
        precord->pact = FALSE;

        status = new_dsxt->add_record(precord);
        if (status) {
            precord->dset = NULL;
            precord->pact = TRUE;
            goto postScanEvent;
        }
    }

    switch (plink->type) { /* New link type */
    case PV_LINK:
        if (plink == &precord->tsel)
            recGblTSELwasModified(plink);
        plink->value.pv_link.precord = precord;

        if (!(plink->value.pv_link.pvlMask & (pvlOptCA|pvlOptCP|pvlOptCPP)) &&
            (dbNameToAddr(plink->value.pv_link.pvname, &dbaddr) == 0)) {
            /* It's a DB link */
            DBADDR      *pdbAddr;

            plink->type = DB_LINK;
            pdbAddr = dbMalloc(sizeof(struct dbAddr));
            *pdbAddr = dbaddr; /* NB: structure copy */;
            plink->value.pv_link.pvt = pdbAddr;
            dbLockSetRecordLock(pdbAddr->precord);
            dbLockSetMerge(precord, pdbAddr->precord);
        } else { /* Make it a CA link */
            char        *pperiod;

            plink->type = CA_LINK;
            if (pfldDes->field_type == DBF_INLINK) {
                plink->value.pv_link.pvlMask |= pvlOptInpNative;
            }
            dbCaAddLink(plink);
            if (pfldDes->field_type == DBF_FWDLINK) {
                pperiod = strrchr(plink->value.pv_link.pvname, '.');
                if (pperiod && strstr(pperiod, "PROC"))
                    plink->value.pv_link.pvlMask |= pvlOptFWD;
            }
        }
        break;

    case CONSTANT:
        break;

    case DB_LINK:
    case CA_LINK:
    case MACRO_LINK:
        break;  /* should never get here */

    default: /* Hardware address */
        if (!isDevLink) {
            status = S_db_badHWaddr;
            goto postScanEvent;
        }
        break;
    }
    db_post_events(precord, plink, DBE_VALUE | DBE_LOG);

restoreScan:
    if (isDevLink &&
        scan == menuScanI_O_Intr) { /* undo scanDelete() */
        precord->scan = scan;
        scanAdd(precord);
    }
postScanEvent:
    if (scan != precord->scan)
        db_post_events(precord, &precord->scan, DBE_VALUE|DBE_LOG);
unlock:
    dbLockSetGblUnlock();
finish:
    dbFinishEntry(&dbEntry);
    return status;
}