/* Get number of events made by attachment */ int et_attach_geteventsmake(et_sys_id id, et_att_id att_id, uint64_t *events) { et_id *etid = (et_id *) id; if (etid->locality == ET_REMOTE) { return etr_attach_geteventsmake(id, att_id, events); } if (!et_alive(id)) { return ET_ERROR_DEAD; } /* Protection from (local) et_close() unmapping shared memory */ et_memRead_lock(etid); /* Has caller already called et_close()? */ if (etid->closed) { et_mem_unlock(etid); if (etid->debug >= ET_DEBUG_ERROR) { et_logmsg("ERROR", "et_attach_geteventsmake, et id is closed\n"); } return ET_ERROR_CLOSED; } if ((att_id < 0) || (att_id >= etid->sys->config.nattachments)) { et_mem_unlock(etid); if (etid->debug >= ET_DEBUG_ERROR) { et_logmsg("ERROR", "et_attach_geteventsmake, bad attachment id\n"); } return ET_ERROR; } if (events != NULL) { *events = etid->sys->attach[att_id].events_make; } et_mem_unlock(etid); return ET_OK; }
/* Wake up a specific attachment waiting to read events.*/ int et_wakeup_attachment(et_sys_id id, et_att_id att) { int status; et_id *etid = (et_id *) id; et_stat_id stat_id; et_station *ps; et_list *pl, *pl_gc; if (att < 0) { if (etid->debug >= ET_DEBUG_ERROR) { et_logmsg("ERROR", "et_wakeup_attachment, bad argument\n"); } return ET_ERROR; } if (etid->locality != ET_LOCAL) { return etr_wakeup_attachment(id, att); } /* Protection from (local) et_close() unmapping shared memory */ et_memRead_lock(etid); /* Has caller already called et_close()? */ if (etid->closed) { et_mem_unlock(etid); if (etid->debug >= ET_DEBUG_ERROR) { et_logmsg("ERROR", "et_wakeup_attachment, et id is closed\n"); } return ET_ERROR_CLOSED; } stat_id = etid->sys->attach[att].stat; ps = etid->grandcentral + stat_id; pl = &ps->list_in; pl_gc = &etid->grandcentral->list_in; if (att >= etid->sys->config.nattachments) { et_mem_unlock(etid); if (etid->debug >= ET_DEBUG_ERROR) { et_logmsg("ERROR", "et_wakeup_attachment, bad argument\n"); } return ET_ERROR; } /* Only tell things to wake up if they are sleeping, otherwise * after the NEXT read, it will quit as if being woken up! */ if ((etid->sys->attach[att].blocked == ET_ATT_UNBLOCKED) && (etid->sys->attach[att].sleep == ET_ATT_NOSLEEP)) { et_mem_unlock(etid); if (etid->debug >= ET_DEBUG_WARN) { et_logmsg("WARN", "et_wakeup_attachment, attachment is NOT blocked so not sending wakeup signal\n"); } return ET_OK; } if (etid->debug >= ET_DEBUG_INFO) { et_logmsg("INFO", "et_wakeup_attachment, waking up attachment %d\n", att); } /* attachment may be waiting on a "get", so wake own station in list */ etid->sys->attach[att].quit = ET_ATT_QUIT; status = pthread_cond_broadcast(&pl->cread); if (status != 0) { err_abort(status, "Wakeup readers"); } /* attachment may be waiting on a "new", so wake GrandCentral's in list */ status = pthread_cond_broadcast(&pl_gc->cread); if (status != 0) { err_abort(status, "Wakeup readers"); } et_mem_unlock(etid); return ET_OK; }
/* Wake up all attachments waiting to read events */ int et_wakeup_all(et_sys_id id, et_stat_id stat_id) { int i, status; et_att_id att; et_id *etid = (et_id *) id; et_station *ps; et_list *pl, *pl_gc; if (stat_id < 0) { if (etid->debug >= ET_DEBUG_ERROR) { et_logmsg("ERROR", "et_wakeup_all, bad argument\n"); } return ET_ERROR; } if (etid->locality != ET_LOCAL) { return etr_wakeup_all(id, stat_id); } /* Protection from (local) et_close() unmapping shared memory */ et_memRead_lock(etid); /* Has caller already called et_close()? */ if (etid->closed) { et_mem_unlock(etid); if (etid->debug >= ET_DEBUG_ERROR) { et_logmsg("ERROR", "et_wakeup_all, et id is closed\n"); } return ET_ERROR_CLOSED; } ps = etid->grandcentral + stat_id; pl = &ps->list_in; pl_gc = &etid->grandcentral->list_in; if (stat_id >= etid->sys->config.nstations) { et_mem_unlock(etid); if (etid->debug >= ET_DEBUG_ERROR) { et_logmsg("ERROR", "et_wakeup_all, bad argument\n"); } return ET_ERROR; } for (i=0; i < etid->sys->config.nattachments ; i++) { att = ps->data.att[i]; if (att > -1) { if ((etid->sys->attach[att].blocked == ET_ATT_BLOCKED) || (etid->sys->attach[att].sleep == ET_ATT_SLEEP)) { etid->sys->attach[att].quit = ET_ATT_QUIT; if (etid->debug >= ET_DEBUG_INFO) { et_logmsg("INFO", "et_wakeup_all, waking up attachment %d\n", att); } } } } /* attachment may be waiting on a "get", so wake own station in list */ status = pthread_cond_broadcast(&pl->cread); if (status != 0) { err_abort(status, "Wakeup all readers"); } /* attachment may be waiting on a "new", so wake GrandCentral's in list */ status = pthread_cond_broadcast(&pl_gc->cread); if (status != 0) { err_abort(status, "Wakeup all readers"); } et_mem_unlock(etid); return ET_OK; }
/** * This routine determines whether we are looking for the ET system locally, * locally on some non-pthread-mutex-sharing operating system, or remotely. * * @param filename name of ET system file. * @param openconfig ET system open configuration. * * @returns @ref ET_REMOTE if looking for a remote ET system. * @returns @ref ET_LOCAL if looking for a local ET system. * @returns @ref ET_LOCAL_NOSHARE if looking for a local ET system without pthread mutex sharing. */ int et_findlocality(const char *filename, et_openconfig openconfig) { char ethost[ET_IPADDRSTRLEN]; et_open_config *config = (et_open_config *) openconfig; /* if local client opens ET system as remote (thru server) ... * This option is for those applications (such as system * monitoring) that only want to communication through * an ET system's server and not map its shared mem. */ if (config->mode == ET_HOST_AS_REMOTE) { return ET_REMOTE; } /* else if ET system host name is unknown and remote ... */ else if (strcmp(config->host, ET_HOST_REMOTE) == 0) { return ET_REMOTE; } /* else if ET system is on local host */ else if ((strcmp(config->host, ET_HOST_LOCAL) == 0) || (strcmp(config->host, "localhost") == 0)) { /* if local operating system can share pthread mutexes ... */ if (et_sharedmutex() == ET_MUTEX_SHARE) { return ET_LOCAL; } else { return ET_LOCAL_NOSHARE; } } /* else if ET system host name is unknown and maybe anywhere ... */ else if (strcmp(config->host, ET_HOST_ANYWHERE) == 0) { int err, port, isLocal; uint32_t inetaddr; struct timeval waittime; waittime.tv_sec = 0; waittime.tv_usec = 10000; /* 0.1 sec */ /* send only 1 broad/multicast with a 0.1 sec wait */ err = et_findserver2(filename, ethost, &port, &inetaddr, NULL, config, 1, &waittime, ET_DEBUG_NONE); if ((err == ET_ERROR) || (err == ET_ERROR_TIMEOUT)) { et_logmsg("ERROR", "et_findlocality, cannot find ET system\n"); return err; } else if (err == ET_ERROR_TOOMANY) { /* many systems responded */ et_logmsg("ERROR", "et_findlocality, multiple ET systems responded\n"); return err; } etNetNodeIsLocal(ethost, &isLocal); if (isLocal) { if (et_sharedmutex() == ET_MUTEX_SHARE) { return ET_LOCAL; } else { return ET_LOCAL_NOSHARE; } } return ET_REMOTE; } /* else ET system host name is given ... */ else { int isLocal; etNetNodeIsLocal(config->host, &isLocal); if (isLocal) { if (et_sharedmutex() == ET_MUTEX_SHARE) { return ET_LOCAL; } else { return ET_LOCAL_NOSHARE; } } return ET_REMOTE; } return ET_REMOTE; }
/** * This routine opens an ET system for client use. * * Given an ET system on the same host, this routine will map the system's shared memory into the * user's space. It also starts up a thread to produce a heartbeat and a second thread to monitor * the ET system's heartbeat. If the ET system is remote, a network connection is made to it.<p> * * The ET system is implemented as a single memory mapped file of the name, filename. * This routine should only be called once, before all other ET routines are used, or after a * system has been closed with a call to @ref et_close or @ref et_forcedclose. A successful return * from this routine assures connection to an ET system which is up and running. * <b><i>IT IS CRUCIAL THAT THE USER GET A RETURN VALUE OF "ET_OK" IF THE USER WANTS AN ET SYSTEM * GUARANTEED TO FUNCTION.</i></b><p> * * The user may open an ET system on a remote host. ET decides whether the user is on the same * as or a different machine than the system. If the determination is made that the user is on * another computer, then network connections are made to that system.<p> * * @param id pointer to ET system id which gets filled in if ET system successfully opened. * @param filename name of ET system file. * @param openconfig ET system open configuration. * * @returns @ref ET_OK if successful * @returns @ref ET_ERROR if bad arg, ET name too long, cannot initialize id, * creating/using shared memory, incompatible values for @ref ET_STATION_SELECT_INTS, * or ET system is 32 bit and this program is 64 bit, * @returns @ref ET_ERROR_TIMEOUT if the ET system is still not active before the routine returns. * @returns @ref ET_ERROR_TOOMANY if broad/multicasting and too many responses * @returns @ref ET_ERROR_REMOTE if broad/multicasting and cannot find/connect to ET system or * cannot allocate memory or ET system & user use different versions of ET, or * the host has a strange byte order. * @returns @ref ET_ERROR_READ if network read error. * @returns @ref ET_ERROR_WRITE if network write error. */ int et_open(et_sys_id *id, const char *filename, et_openconfig openconfig) { int status, auto_open=0, err, locality; et_open_config *config; et_openconfig auto_config = NULL; int def_debug; if (openconfig == NULL) { auto_open = 1; if (et_open_config_init(&auto_config) == ET_ERROR) { et_logmsg("ERROR", "et_open, null arg for openconfig, cannot use default\n"); return ET_ERROR; } openconfig = auto_config; } config = (et_open_config *) openconfig; err = ET_OK; /* argument checking */ if ((filename == NULL) || (config->init != ET_STRUCT_OK)) { et_logmsg("ERROR", "et_open, bad argument\n"); err = ET_ERROR; } else if (strlen(filename) > ET_FILENAME_LENGTH - 1) { et_logmsg("ERROR", "et_open, ET name too long\n"); err = ET_ERROR; } if (err != ET_OK) { if (auto_open == 1) { et_open_config_destroy(auto_config); } return err; } /* initialize id */ if (et_id_init(id) != ET_OK) { et_logmsg("ERROR", "et_open, cannot initialize id\n"); return ET_ERROR; } if (et_open_config_getdebugdefault(openconfig, &def_debug) != ET_OK) { def_debug = ET_DEBUG_ERROR; } et_system_setdebug(*id, def_debug); /* Decide whether we are looking for the ET system locally, * locally on some non-mutex-sharing operating * system, remotely, or anywhere. */ locality = et_findlocality(filename, openconfig); /* if host is local ... */ if (locality == ET_LOCAL) { status = etl_open(id, filename, openconfig); /* If this is a Java-based ET sys, try opening it as remote client. */ if (status == ET_ERROR_JAVASYS) { et_logmsg("ERROR", "et_open: cannot open Java ET file, try as remote client\n"); status = etr_open(id, filename, openconfig); } } /* else if host is remote ... */ else if (locality == ET_REMOTE) { status = etr_open(id, filename, openconfig); } /* else if host is local on Linux ... */ else if (locality == ET_LOCAL_NOSHARE) { status = etn_open(id, filename, openconfig); } /* else if too many systems responded and we have return error policy ... */ else if ((locality == ET_ERROR_TOOMANY) && (config->policy == ET_POLICY_ERROR)) { if (auto_open == 1) { et_open_config_destroy(auto_config); } et_logmsg("ERROR", "et_open: too many ET systems of that name responded\n"); return ET_ERROR; } /* else did not find ET system by broad/multicasting. In * this case, try to open a local system first then remote. */ else { int shared = et_sharedmutex(); /* if local operating system can share pthread mutexes ... */ if (shared == ET_MUTEX_SHARE) { status = etl_open(id, filename, openconfig); } else { status = etn_open(id, filename, openconfig); } if (status != ET_OK) { status = etr_open(id, filename, openconfig); } } if (status != ET_OK) { et_id_destroy(*id); } if (auto_open == 1) { et_open_config_destroy(auto_config); } return status; }
int et_open(et_sys_id *id, const char *filename, et_openconfig openconfig) { int status, auto_open=0, err; et_open_config *config; et_openconfig auto_config = NULL; int def_debug; if (openconfig == NULL) { auto_open = 1; if (et_open_config_init(&auto_config) == ET_ERROR) { et_logmsg("ERROR", "et_open, null arg for openconfig, cannot use default\n"); return ET_ERROR; } openconfig = auto_config; } config = (et_open_config *) openconfig; err = ET_OK; /* argument checking */ if ((filename == NULL) || (config->init != ET_STRUCT_OK)) { et_logmsg("ERROR", "et_open, bad argument\n"); err = ET_ERROR; } else if (strlen(filename) > ET_FILENAME_LENGTH - 1) { et_logmsg("ERROR", "et_open, ET name too long\n"); err = ET_ERROR; } if (err != ET_OK) { if (auto_open == 1) { et_open_config_destroy(auto_config); } return err; } /* initialize id */ if (et_id_init(id) != ET_OK) { et_logmsg("ERROR", "et_open, cannot initialize id\n"); return ET_ERROR; } if (et_open_config_getdebugdefault(openconfig, &def_debug) != ET_OK) { def_debug = ET_DEBUG_ERROR; } et_system_setdebug(*id, def_debug); /* We depart from the original version of et_open since * this ET client will attach to an ET system remotely by definition. * Force the configuration to make a tcp connection to the ET system, * even if it's not remote. */ config->mode = ET_HOST_AS_REMOTE; status = etr_open(id, filename, openconfig); if (status != ET_OK) { et_id_destroy(*id); } if (auto_open == 1) { et_open_config_destroy(auto_config); } return status; }