Example #1
0
void
SessionSummaryThr::run()
{
	if ( mysqlpp::get_library_version() != MYSQLPP_HEADER_VERSION )
	{
		cerr<< "Library/header version number mismatch" << endl;
		return;
	};
	MyNode  mynode(mpSession);
	//mynode.prevshotnum = startshot;
	SEVCHK(ca_context_create(ca_disable_preemptive_callback),"ca_context_create");
	SEVCHK(ca_add_exception_event(exceptionCallback,NULL), "ca_add_exception_event");
	//string pvnames[]={"CCS_SHOT_NUMBER","CCS_PERFORM_SHOT_SUMMARY"};
	//Test..
	//SEVCHK(ca_create_channel("DDS2_getState",connectionCallback,
	//			&mynode,10,(oldChannelNotify**)&mynode.summary_chid), "ca_create_channel");
	SEVCHK(ca_create_channel("CCS_PERFORM_SHOT_SUMMARY",connectionCallback,
				&mynode,10,(oldChannelNotify**)&mynode.summary_chid), "ca_create_channel");
	SEVCHK(ca_replace_access_rights_event(mynode.summary_chid,
				accessRightsCallback), "ca_replace_access_rights_event");
	ca_create_subscription (DBR_TIME_LONG, 0, mynode.summary_chid, DBE_VALUE|DBE_ALARM, eventCallback, (void*)&mynode, NULL);

	/*Should never return from following call*/
	SEVCHK(ca_pend_event(0.0),"ca_pend_event");
}
static void caDelete(Record *pr)
{
    int status;
    Channel *pCh;

    if(!pr) return;
    pCh = &((caTask.pages[pr->caId/CA_PAGE_SIZE])
      [pr->caId % CA_PAGE_SIZE]);
    if(ca_state(pCh->chid) == cs_conn)
      caTask.channelConnected--;
#if 0
  /* KE: This is not necessary according to Jeff */
    ca_change_connection_event(pCh->chid,NULL);
    ca_replace_access_rights_event(pCh->chid,NULL);
#endif
    if(pCh->evid) {
	status = ca_clear_event(pCh->evid);
	if(status != ECA_NORMAL) {
	    medmPostMsg(1,"caDelete: ca_clear_event failed: %s\n",
	      ca_message(status));
	    return;
	}
    }
    pCh->evid = NULL;
    if(pCh->chid) {
	status = ca_clear_channel(pCh->chid);
	if(status != ECA_NORMAL) {
	    medmPostMsg(1,"caDelete: ca_clear_channel failed: %s\n",
	      ca_message(status));
	    return;
	}
    }
    pCh->chid = NULL;
    if(pCh->data) {
	free((char *)pCh->data);
	pCh->data = NULL;
    }
    if(caTask.freeListCount >= caTask.freeListSize) {
	caTask.freeListSize += CA_PAGE_SIZE;
#if defined(__cplusplus) && !defined(__GNUG__)
	caTask.freeList = (int *) realloc((malloc_t)caTask.freeList,
	  sizeof(int)*caTask.freeListSize);
#else
	caTask.freeList = (int *) realloc(caTask.freeList,
	  sizeof(int)*caTask.freeListSize);
#endif
	if(caTask.freeList == NULL) {
	    medmPostMsg(1,"caDelete: Memory allocation error\n");
	    return;
	}
    }
    caTask.freeList[caTask.freeListCount] = pCh->caId;
    caTask.freeListCount++;
    caTask.channelCount--;
#if DEBUG_ADD
    print("caAdd: channelCount=%3d\n",caTask.channelCount);
#endif
}
Example #3
0
int main(int argc, char** argv)
{
	fd_set rfds;
	int tot;
	struct timeval tv;

	if(argc!=3)
	{
		fprintf(stderr,"Usage: %s PV_to_monitor script_to_run\n\n",argv[0]);
		fprintf(stderr,"This program monitored PV PV_to_monitor and\n");
		fprintf(stderr,"runs and executes script_to_run, which can be\n");
		fprintf(stderr,"any program or executable script.\n");
		fprintf(stderr,"The script or program gets invoked with the first\n");
		fprintf(stderr,"argument as the PV name and the second argument\n");
		fprintf(stderr,"as the value of the PV\n");
		fprintf(stderr,"The program or shell script script_to_run is\n");
		fprintf(stderr,"run as a separate child process of this program\n");
		fprintf(stderr,"This means that your script or program will not\n");
		fprintf(stderr,"stop this process from running, if fact your\n");
		fprintf(stderr,"script or program can be invoked many times if\n");
		fprintf(stderr,"the value of the PV is changing rapidly and\n");
		fprintf(stderr,"several instances of your program could be running\n");
		fprintf(stderr,"simultaneously.\n");
		return -1;
	}

	strcpy(pv_name,argv[1]);
	script_name=argv[2];
	pv_value[0]='\0';

	if(access(script_name,X_OK)<0)
	{
		fprintf(stderr,"Script %s not found or not executable\n",script_name);
		return -1;
	}

	signal(SIGINT,sig_func);
	signal(SIGQUIT,sig_func);
	signal(SIGTERM,sig_func);
	signal(SIGHUP,sig_func);
	signal(SIGCHLD,sig_chld);

	FD_ZERO(&all_fds);

	SEVCHK(ca_task_initialize(),"task initialize");
	SEVCHK(ca_add_fd_registration(fdCB,&all_fds),"add fd registration");
	SEVCHK(ca_add_exception_event(exCB,NULL),"add exception event");

	SEVCHK(ca_search_and_connect(pv_name,&id,conCB,NULL),
		"search and connect");
	SEVCHK(ca_replace_access_rights_event(id,accCB),
		"replace access rights event");

	/* SEVCHK(ca_add_event(DBR_TIME_STRING,data.id,evCB,&data,&data.event),
		"add event"); */

	ca_pend_event(REALLY_SMALL);

	/* fprintf(stderr,"Monitoring <%s>\n",pv_name); */

	while(do_not_exit)
	{
		rfds=all_fds;
		tv.tv_sec=1;
		tv.tv_usec=0; /*200000*/;

		switch(tot=select(FD_SETSIZE,&rfds,NULL,NULL,&tv))
		{
		/*
		case -1:
			perror("select error - bad");
			break;
		*/
		case 0:
			ca_pend_event(REALLY_SMALL);
			break;
		default:
			/* fprintf(stderr,"select data ready\n"); */
			ca_pend_event(REALLY_SMALL);
			break;
		}
	}

	fprintf(stderr,"PV monitor program is exiting!\n");
	ca_task_exit();
	return 0;
}
Example #4
0
/*
 * callback from connection handler: change the state of the channel valid
 * flag depending on the connection being up or down.
 * ASSUMPTIONS: chan_id is valid.
 */
static void
connect_callback(struct connection_handler_args args)
{
    Connector *conp;
    
    Channel *chan = ca_puser( args.chid);
    int status;
    
    DEBUGP printf("connect callback %p\n", chan);
    switch( args.op)
    {
    case CA_OP_CONN_UP:
    	if( chan->initData == 1)
	{
		chan->maxelement = ca_element_count(chan->chan_id);
		chan->chan_type = ca_field_type(chan->chan_id);
		chan->initData = 0;
	}
	/*
	 * note that a dropped and recreated connection can cause a free and alloc. This
	 * is not always redundant, as software may have restarted with different sizes
	 * for the field!
	 */
	if( chan->createData == 1 )
	{
		if( chan->dataval)
			free( chan->dataval);
		chan->dataval = calloc(dbr_size[chan->chan_type], chan->maxelement+1);
	}

	chan->readAccess = ca_read_access( chan->chan_id);
	chan->writeAccess = ca_write_access( chan->chan_id);
	status = ca_array_get_callback( dbf_type_to_DBR_CTRL(ca_field_type(chan->chan_id)), 1, chan->chan_id, getChanInfo, (void*)chan);
	SEVCHK(status, "connect_callback : ca_get_DBR_CTRL_event failed");
	status = ca_replace_access_rights_event( chan->chan_id, getAccessRights);
	SEVCHK(status, "connect_callback : ca_replace_access_rights_event failed");

	chan->valid = 1;
	chan->outstanding = 0;
	if( chan->monitor)
	{
	    chan->status = 100;	/* MAGIC: an absurd status */
	    status = ca_add_array_event(dbf_type_to_DBR_STS(chan->chan_type), chan->maxelement, chan->chan_id, monitorCallback, chan, 
		    		(double) 0.0, (double) 0.0, (double) 0.0, &(chan->eventId));
	    SEVCHK(status, "connect_callback : ca_add_event failed");
	    status = ca_flush_io();
	    SEVCHK(status, "connect_callback : ca_flush_io failed");
	}
	break;
	
    case CA_OP_CONN_DOWN:
	if( chan->valid && chan->eventId)
	    ca_clear_event(chan->eventId);
	chan->valid = 0;
	chan->status = 99;
	
	/*
	 * update the access rights and severity for all the connectors
	 */
	for(conp=chan->first_connector; conp ; conp=conp->next)
	{
	    if(conp->newAccess)
		(*conp->newAccess)(conp);
	    if( conp->newState)
	    	(*conp->newState)(conp);
	}
	
	break;
    default:
	break;
    }

    return;
}
Example #5
0
void SinglePlotThread::run()
{
#if 0
	// event gathering
	//printchannel();	//for Debug
	mutex.lock();
	mynode.plot	= m_plot;
	chid unit_chid;
	dbr_string_t units;
	QString unitch = m_pvname + ".EGU";
	ca_create_channel(unitch.toStdString().c_str(), 0, 0, 0, &unit_chid);
	ca_pend_io(0.1);
	ca_get(DBR_STRING, unit_chid, (void *)&units);
	ca_pend_io(0.1);
	m_plot->SetUnit(units);

	ca_create_channel(m_pvname.toStdString().c_str(), connectionCallback, &mynode, 0, (oldChannelNotify**)&mynode.mychid);
	ca_replace_access_rights_event(mynode.mychid, accessRightsCallback);
	ca_create_subscription (DBR_TIME_DOUBLE, 0, mynode.mychid, DBE_VALUE|DBE_ALARM, eventCallback, &mynode, &mynode.myevid);
	//ca_add_event(DBR_GR_DOUBLE, mynode.mychid, eventCallback, &mynode, &mynode.myevid);
	mutex.unlock();
	ca_pend_event(0.0);
#else
	//periodic gathering
	mutex.lock();
	chid unit_chid, val_chid;
	dbr_string_t units;

	QString unitch = m_pvname + ".EGU";
	ca_create_channel(unitch.toStdString().c_str(), 0, 0, 0, &unit_chid); ca_pend_io(0.2);
	ca_get(DBR_STRING, unit_chid, (void *)&units); ca_pend_io(0.2);
	m_plot->SetUnit(units);

	struct dbr_time_double data;
	ca_create_channel(m_pvname.toStdString().c_str(), 0, 0, 0, &val_chid);
	ca_pend_io(0.2);

	epicsTime  stamp;

	struct local_tm_nano_sec tm;
	int totsec = 0;
	//for periodic single plot local time
	int year, month, day, hour, min, sec;
	int factor = 1;
	switch(mperiodic)
	{
		case PointOne:
			factor *= 0.1;
			break;
		case PointFive:
			factor *= 0.5;
			break;
		case FiveSec:
			factor *= 5;
			break;
		case TenSec:
			factor *= 10;
			break;
		case OneSec:
		default:
			break;
	};
	while(getStop()==false)
	{
		ca_get(DBR_TIME_DOUBLE, val_chid, (void *)&data);
		ca_pend_io(0.2);
		//qDebug("%s : %f\n",ca_name(val_chid), data.value);
		Epoch2Datetime(year, month, day, hour, min, sec);
#if 0
		stamp = data.stamp;
		tm = (local_tm_nano_sec) stamp;
		totsec = tm.ansi_tm.tm_hour*3600+tm.ansi_tm.tm_min*60+tm.ansi_tm.tm_sec;
		m_plot->GetValue(data.value, totsec,tm.ansi_tm.tm_year,tm.ansi_tm.tm_mon, tm.ansi_tm.tm_mday );
#else
		totsec = hour*3600+min*60+sec;
		m_plot->GetValue(data.value, totsec, year, month, day);
#endif
		usleep(1000000*factor);
	};
	//ca_clear_channel(unit_chid);
	//ca_clear_channel(val_chid);
	ca_context_destroy();
	mutex.unlock();
	exit();
	qDebug("SinglePlot Exit");
#endif
}
Example #6
0
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);
}
static void medmConnectEventCb(struct connection_handler_args args) {
    int status;
    Channel *pCh = (Channel *)ca_puser(args.chid);
    int count;

  /* Increment the event counter */
    caTask.caEventCount++;

  /* Check for valid values */
    if(globalDisplayListTraversalMode != DL_EXECUTE) return;
    if(!pCh || !pCh->chid || !pCh->pr) {
	medmPostMsg(0,"medmConnectEventCb: Invalid channel information\n");
	return;
    }

  /* Do a get every time a channel is connected or reconnected and has
   * read access.  The get will cause the graphical info callback to
   * be called */
    if(args.op == CA_OP_CONN_UP && ca_read_access(pCh->chid)) {
	status = ca_array_get_callback(
	  dbf_type_to_DBR_CTRL(ca_field_type(args.chid)),
	  1, args.chid, medmUpdateGraphicalInfoCb, NULL);
	if(status != ECA_NORMAL) {
	    medmPostMsg(0,"medmConnectEventCb: "
	      "ca_array_get_callback [%s]:\n %s\n",
	      ca_name(pCh->chid)?ca_name(pCh->chid):"Unknown",
	      ca_message(status));
#if DEBUG_CONNECTION
# if 0
	    system("netstat | grep iocacis");
# endif
	    print("  pCh->chid %s args.chid\n",
	      pCh->chid == args.chid?"==":"!=");
	    print(
	      "  Channel Name: %s\n"
	      "  State: %s\n"
	      "  Native Type: %s\n"
	      "  Native Count: %hu\n"
	      "  Access: %s%s\n"
	      "  IOC: %s\n",
	      args.chid?ca_name(args.chid):"Unavailable",
	      args.chid?ca_state(args.chid) == cs_never_conn?"Never":
	      ca_state(args.chid) == cs_prev_conn?"Prev":
	      ca_state(args.chid) == cs_conn?"Conn":
	      ca_state(args.chid) == cs_closed?"Closed":"Unknown":"Unavailable",
	      args.chid?dbf_type_to_text(ca_field_type(args.chid)):"Unavailable",
	      args.chid?ca_element_count(args.chid):0,
	      args.chid?(ca_read_access(args.chid)?"R":"None"):"Unavailable",
	      args.chid?(ca_write_access(args.chid)?"W":""):"",
	      args.chid?ca_host_name(args.chid):"Unavailable");
#endif
	}
    }

  /* Handle four cases: connected or not and previously connected or not */
    if(args.op == CA_OP_CONN_UP) {
      /* Connected */
	if(pCh->previouslyConnected == False) {
	  /* Connected and not previously connected */
	  /* Set these first so they will be right for the updateValueCb */
	    pCh->pr->elementCount = ca_element_count(pCh->chid);
	    pCh->pr->dataType = ca_field_type(args.chid);
	    pCh->pr->connected = True;
	    caTask.channelConnected++;
	  /* Add the access-rights-change callback and the
	     significant-change (value, alarm or severity)
	     callback. Don't call the updateValueCb because
	     ca_replace_access_rights_event will call it. */
	    status = ca_replace_access_rights_event(
	      pCh->chid,medmReplaceAccessRightsEventCb);
	    if(status != ECA_NORMAL) {
		medmPostMsg(0,"medmConnectEventCb: "
		  "ca_replace_access_rights_event [%s]: %s\n",
		  ca_name(pCh->chid)?ca_name(pCh->chid):"Unknown",
		  ca_message(status));
	    }
	    if(pCh->pr->currentCount == -2) {
                count=0;
            } else {
                count=ca_element_count(pCh->chid);
            }
#ifdef __USING_TIME_STAMP__
	    status = ca_add_array_event(
	      dbf_type_to_DBR_TIME(ca_field_type(pCh->chid)),
	      count, pCh->chid,
	      medmUpdateChannelCb, pCh, 0.0,0.0,0.0, &(pCh->evid));
#else
	    status = ca_add_array_event(
	      dbf_type_to_DBR_STS(ca_field_type(pCh->chid)),
	      count, pCh->chid,
	      medmUpdateChannelCb, pCh, 0.0,0.0,0.0, &(pCh->evid));
#endif
	    if(status != ECA_NORMAL) {
	      /* Set the pointer to NULL in case CA didn't.  We don't
                 want to use it or clear it later. */
#if DEBUG_CONNECTION
		if(!pCh->evid) {
		    print("medmConnectEventCb: ca_add_array_event: \n"
		      "  status[%d] != ECA_NORMAL and pCh->evid != NULL\n",
		      status);
		}
#endif
		pCh->evid = NULL;
		medmPostMsg(0,"medmConnectEventCb: "
		  "ca_add_array_event [%s]:\n %s\n",
		  ca_name(pCh->chid)?ca_name(pCh->chid):"Unknown",
		  ca_message(status));
#if DEBUG_CONNECTION
# if 0
		system("netstat | grep iocacis");
# endif
		print("  pCh->chid %s args.chid\n",
		  pCh->chid == args.chid?"==":"!=");
		print(
		  "  Channel Name: %s\n"
		  "  State: %s\n"
		  "  Native Type: %s\n"
		  "  Native Count: %hu\n"
		  "  Access: %s%s\n"
		  "  IOC: %s\n",
		  args.chid?ca_name(args.chid):"Unavailable",
		  args.chid?ca_state(args.chid) == cs_never_conn?"Never":
		  ca_state(args.chid) == cs_prev_conn?"Prev":
		  ca_state(args.chid) == cs_conn?"Conn":
		  ca_state(args.chid) == cs_closed?"Closed":"Unknown":"Unavailable",
		  args.chid?dbf_type_to_text(ca_field_type(args.chid)):"Unavailable",
		  args.chid?ca_element_count(args.chid):0,
		  args.chid?(ca_read_access(args.chid)?"R":"None"):"Unavailable",
		  args.chid?(ca_write_access(args.chid)?"W":""):"",
		  args.chid?ca_host_name(args.chid):"Unavailable");
#endif
	    }
	  /* Set this one last so ca_replace_access_rights_event can
             use the old value */
	    pCh->previouslyConnected = True;
	} else {
	  /* Connected and previously connected */
	    pCh->pr->connected = True;
	    caTask.channelConnected++;
	    if(pCh->pr->updateValueCb)
	      pCh->pr->updateValueCb((XtPointer)pCh->pr);
	}
    } else {
      /* Not connected */
	if(pCh->previouslyConnected == False) {
	  /* Not connected and not previously connected */
	  /* Probably doesn't happen -- if CA can't connect, this
	   *   routine never gets called */
	    pCh->pr->connected = False;
	} else {
	  /* Not connected but previously connected */
	    pCh->pr->connected = False;
	    caTask.channelConnected--;
	    if(pCh->pr->updateValueCb)
	      pCh->pr->updateValueCb((XtPointer)pCh->pr);
	}
    }
}