static int ulapi_load(rtapi_switch_t **ulapi_switch) { int retval; const char *errmsg; rtapi_get_handle_t rtapi_get_handle; char ulapi_lib_fname[PATH_MAX]; char *instance = getenv("INSTANCE"); char *debug_env = getenv("ULAPI_DEBUG"); int size = 0; int globalkey; // set the rtapi_instance global for this hal library instance if (instance != NULL) rtapi_instance = atoi(instance); if (debug_env) ulapi_debug = atoi(debug_env); rtapi_set_msg_level(ulapi_debug); // tag message origin field rtapi_set_logtag("ulapi"); // first thing is to attach the global segment, based on // the RTAPI instance id. This will contain the flavor // this ULAPI HAL instance is to run with. // Also, it's the prerequisite for common error message // handling through the message ringbuffer; unless then // error messages will go to stderr. // the global segment is attached once here per ULAPI instance; // it's address is passed to the ulapi-<flavor>.so module once loaded. // init the common shared memory driver APU shm_common_init(); globalkey = OS_KEY(GLOBAL_KEY, rtapi_instance); retval = shm_common_new(globalkey, &size, rtapi_instance, (void **) &global_data, 0); if (retval == -ENOENT) { // the global_data segment does not exist. Happens if the realtime // script was not started rtapi_print_msg(RTAPI_MSG_ERR, "ULAPI:%d ERROR: realtime not started\n", rtapi_instance); return retval; } if (retval < 0) { // some other error attaching global rtapi_print_msg(RTAPI_MSG_ERR, "ULAPI:%d ERROR: shm_common_new() failed key=0x%x %s\n", rtapi_instance, globalkey, strerror(-retval)); return retval; } if (size != sizeof(global_data_t)) { rtapi_print_msg(RTAPI_MSG_ERR, "ULAPI:%d ERROR: global segment size mismatch," " expected: %zd, actual:%d\n", rtapi_instance, sizeof(global_data_t), size); return -EINVAL; } if (global_data->magic != GLOBAL_READY) { rtapi_print_msg(RTAPI_MSG_ERR, "ULAPI:%d ERROR: global segment invalid magic:" " expected: 0x%x, actual: 0x%x\n", rtapi_instance, GLOBAL_READY, global_data->magic); return -EINVAL; } // global data set up ok // obtain handle on flavor descriptor as detected by rtapi_msgd flavor = flavor_byid(global_data->rtapi_thread_flavor); if (flavor == NULL) { rtapi_print_msg(RTAPI_MSG_ERR, "HAL_LIB:%d BUG - invalid flavor id: %d\n", rtapi_instance, global_data->rtapi_thread_flavor); return -EINVAL; } snprintf(ulapi_lib_fname,PATH_MAX,"%s/%s-%s%s", EMC2_RTLIB_DIR, ulapi_lib, flavor->name, flavor->so_ext); // dynload the proper ulapi.so: if ((ulapi_so = dlopen(ulapi_lib_fname, RTLD_GLOBAL|RTLD_NOW)) == NULL) { errmsg = dlerror(); rtapi_print_msg(RTAPI_MSG_ERR, "HAL_LIB:%d FATAL - dlopen(%s) failed: %s\n", rtapi_instance, ulapi_lib_fname, errmsg ? errmsg : "NULL"); return -ENOENT; } // resolve rtapi_switch getter function dlerror(); if ((rtapi_get_handle = (rtapi_get_handle_t) dlsym(ulapi_so, "rtapi_get_handle")) == NULL) { errmsg = dlerror(); rtapi_print_msg(RTAPI_MSG_ERR, "HAL_LIB:%d FATAL - resolving %s: cant" " dlsym(rtapi_get_handle): %s\n", rtapi_instance, ulapi_lib, errmsg ? errmsg : "NULL"); return -ENOENT; } assert(rtapi_get_handle != NULL); // this redirects calls to rtapi through the just-loaded ulapi *ulapi_switch = rtapi_get_handle(); // from here on it is safe to call all RTAPI functions (i.e. including those // which go through rtapi_switch) // resolve main function dlerror(); if ((ulapi_main_ref = (ulapi_main_t) dlsym(ulapi_so, "ulapi_main")) == NULL) { errmsg = dlerror(); rtapi_print_msg(RTAPI_MSG_ERR, "HAL_LIB:%d FATAL - resolving %s: " "cant dlsym(ulapi_main): %s\n", rtapi_instance, ulapi_lib, errmsg ? errmsg : "NULL"); return -ENOENT; } // resolve exit function dlerror(); if ((ulapi_exit_ref = (ulapi_exit_t) dlsym(ulapi_so, "ulapi_exit")) == NULL) { errmsg = dlerror(); rtapi_print_msg(RTAPI_MSG_ERR, "HAL_LIB: FATAL - resolving %s:" " cant dlsym(ulapi_exit): %s\n", ulapi_lib, errmsg ? errmsg : "NULL"); return -ENOENT; } assert(ulapi_main_ref != NULL); assert(ulapi_exit_ref != NULL); // call the ulapi init method, passing in the global segment if ((retval = ulapi_main_ref(rtapi_instance, flavor->id, global_data)) < 0) { // check shmdrv, permissions rtapi_print_msg(RTAPI_MSG_ERR, "HAL_LIB: FATAL - cannot attach to instance %d" " - realtime not started?\n", rtapi_instance); return -ENOENT; } // pretty bad - we loaded the wrong ulapi.so if (flavor->id != rtapi_switch->thread_flavor_id) { rtapi_print_msg(RTAPI_MSG_ERR, "HAL_LIB: BUG: thread flavors disagree:" " hal_lib.c=%d rtapi=%d\n", flavor->id, rtapi_switch->thread_flavor_id); } // sanity check - may be harmless if (strcmp(GIT_VERSION, rtapi_switch->git_version)) { rtapi_print_msg(RTAPI_MSG_WARN, "HAL_LIB: UP API warning - git versions disagree:" " hal_lib.c=%s %s=%s\n", GIT_VERSION, ulapi_lib, rtapi_switch->git_version); } // declare victory return 0; }
int _rtapi_shmem_new_inst(int userkey, int instance, int module_id, unsigned long int size) { shmem_data *shmem; int i, ret, actual_size; int is_new = 0; int key = OS_KEY(userkey, instance); static int page_size; if (!page_size) page_size = sysconf(_SC_PAGESIZE); rtapi_mutex_get(&(rtapi_data->mutex)); for (i = 1 ; i < RTAPI_MAX_SHMEMS; i++) { if (shmem_array[i].magic == SHMEM_MAGIC && shmem_array[i].key == key) { shmem_array[i].count ++; rtapi_mutex_give(&(rtapi_data->mutex)); return i; } if (shmem_array[i].magic != SHMEM_MAGIC) break; } if (i == RTAPI_MAX_SHMEMS) { rtapi_mutex_give(&(rtapi_data->mutex)); rtapi_print_msg(RTAPI_MSG_ERR, "rtapi_shmem_new failed due to RTAPI_MAX_SHMEMS\n"); return -ENOMEM; } shmem = &shmem_array[i]; // redefine size == 0 to mean 'attach only, dont create' actual_size = size; ret = shm_common_new(key, &actual_size, instance, &shmem->mem, size > 0); if (ret > 0) is_new = 1; if (ret < 0) { rtapi_mutex_give(&(rtapi_data->mutex)); rtapi_print_msg(RTAPI_MSG_ERR, "shm_common_new:%d failed key=0x%x size=%ld\n", instance, key, size); return ret; } // a non-zero size was given but it didn match what we found: if (size && (actual_size != size)) { rtapi_print_msg(RTAPI_MSG_ERR, "rtapi_shmem_new:%d 0x8.8%x: requested size %ld and actual size %d dont match\n", instance, key, size, actual_size); } /* Touch each page by either zeroing the whole mem (if it's a new SHM region), or by reading from it. */ if (is_new) { memset(shmem->mem, 0, size); } else { unsigned int i; for (i = 0; i < size; i += page_size) { unsigned int x = *(volatile unsigned int *) ((unsigned char *)shmem->mem + i); /* Use rand_r to clobber the read so GCC won't optimize it out. */ rand_r(&x); } } /* label as a valid shmem structure */ shmem->magic = SHMEM_MAGIC; /* fill in the other fields */ shmem->size = actual_size; shmem->key = key; shmem->count = 1; shmem->instance = instance; rtapi_mutex_give(&(rtapi_data->mutex)); /* return handle to the caller */ return i; }
static int create_global_segment() { int retval = 0; int globalkey = OS_KEY(GLOBAL_KEY, rtapi_instance); int rtapikey = OS_KEY(RTAPI_KEY, rtapi_instance); int halkey = OS_KEY(HAL_KEY, rtapi_instance); int global_exists = shm_common_exists(globalkey); int hal_exists = shm_common_exists(halkey); int rtapi_exists = shm_common_exists(rtapikey); if (global_exists || rtapi_exists || hal_exists) { // hm, something is wrong here pid_t msgd_pid = pid_of("msgd:%d", rtapi_instance); if (rtapi_instance == kernel_instance_id()) { // collision with a running kernel instance - not good. int shmdrv_loaded = is_module_loaded("shmdrv"); int rtapi_loaded = is_module_loaded("rtapi"); int hal_loaded = is_module_loaded("hal_lib"); fprintf(stderr, "ERROR: found existing kernel " "instance with the same instance id (%d)\n", rtapi_instance); fprintf(stderr,"kernel modules loaded: %s%s%s\n", shmdrv_loaded ? "shmdrv " : "", rtapi_loaded ? "rtapi " : "", hal_loaded ? "hal_lib " : ""); if (msgd_pid > 0) fprintf(stderr,"the msgd process msgd:%d is " "already running, pid: %d\n", rtapi_instance, msgd_pid); else fprintf(stderr,"msgd:%d not running!\n", rtapi_instance); return -EEXIST; } // running userthreads instance? pid_t app_pid = pid_of("rtapi:%d", rtapi_instance); if ((msgd_pid > -1) || (app_pid > -1)) { fprintf(stderr, "ERROR: found existing user RT " "instance with the same instance id (%d)\n", rtapi_instance); if (msgd_pid > 0) fprintf(stderr,"the msgd process msgd:%d is " "already running, pid: %d\n", rtapi_instance, msgd_pid); else fprintf(stderr,"msgd:%d not running!\n", rtapi_instance); if (app_pid > 0) fprintf(stderr,"the RT process rtapi:%d is " "already running, pid: %d\n", rtapi_instance, app_pid); else fprintf(stderr,"the RT process rtapi:%d not running!\n", rtapi_instance); // TBD: might check for other user HAL processes still // around. This might work with fuser on the HAL segment // but might be tricky wit shmdrv. return -EEXIST; } // leftover shared memory segments were around, but no using // entities (user process or kernel modules). // Remove and keep going: if (shmdrv_loaded) { // since neiter rtapi.ko nor hal_lib.ko is loaded // cause a garbage collect in shmdrv shmdrv_gc(); } else { // Posix shm case. char segment_name[LINELEN]; if (hal_exists) { sprintf(segment_name, SHM_FMT, rtapi_instance, halkey); fprintf(stderr,"warning: removing unused HAL shm segment %s\n", segment_name); if (shm_unlink(segment_name)) perror(segment_name); } if (rtapi_exists) { sprintf(segment_name, SHM_FMT, rtapi_instance, rtapikey); fprintf(stderr,"warning: removing unused RTAPI" " shm segment %s\n", segment_name); if (shm_unlink(segment_name)) perror(segment_name); } if (global_exists) { sprintf(segment_name, SHM_FMT, rtapi_instance, globalkey); fprintf(stderr,"warning: removing unused global" " shm segment %s\n", segment_name); if (shm_unlink(segment_name)) perror(segment_name); } } } // now try again: if (shm_common_exists(globalkey)) { fprintf(stderr, "MSGD:%d ERROR: found existing global segment key=0x%x\n", rtapi_instance, globalkey); return -EEXIST; } int size = sizeof(global_data_t); retval = shm_common_new(globalkey, &size, rtapi_instance, (void **) &global_data, 1); if (retval < 0) { fprintf(stderr, "MSGD:%d ERROR: cannot create global segment key=0x%x %s\n", rtapi_instance, globalkey, strerror(-retval)); } if (size != sizeof(global_data_t)) { fprintf(stderr, "MSGD:%d ERROR: global segment size mismatch: expect %d got %d\n", rtapi_instance, sizeof(global_data_t), size); return -EINVAL; } return retval; }
int ulapi_main(int instance, int flavor, global_data_t *global) { int retval = 0; int rtapikey; int size = 0; rtapi_instance = instance; // from here on global within ulapi.so // shm_common_init(); // common shared memory API needs this // the HAL library constructor already has the global // shm segment attached, so no need to do it again here // since we're not using the rtapi_app_init()/rtapi_app_exit() // calling conventions might as well pass it it // this sets global_data for use within ulapi.so which // has a disjoint symbol namespace from hal_lib global_data = global; rtapi_print_msg(RTAPI_MSG_DBG,"ULAPI:%d %s %s init\n", rtapi_instance, rtapi_get_handle()->thread_flavor_name, GIT_VERSION); if (rtapi_switch->thread_flavor_flags & FLAVOR_RTAPI_DATA_IN_SHM) { rtapikey = OS_KEY(RTAPI_KEY, rtapi_instance); // attach to existing RTAPI segment // not all thread flavors actuall might use it if ((retval = shm_common_new(rtapikey, &size, rtapi_instance, (void **) &rtapi_data, 0))) { rtapi_print_msg(RTAPI_MSG_ERR, "ULAPI:%d ERROR: cannot attach rtapi" " segment key=0x%x %s\n", rtapi_instance, rtapikey, strerror(-retval)); } if (size != sizeof(rtapi_data_t)) { rtapi_print_msg(RTAPI_MSG_ERR, "ULAPI:%d ERROR: unexpected rtapi shm size:" " expected: %zu actual: %d\n", rtapi_instance, sizeof(rtapi_data_t), size); return -EINVAL; } if (MMAP_OK(global_data) && MMAP_OK(rtapi_data)) { rtapi_print_msg(RTAPI_MSG_DBG, "ULAPI:%d msglevel=%d/%d halsize=%d" " %s startup %s\n", rtapi_instance, global_data->rt_msg_level, global_data->user_msg_level, global_data->hal_size, GIT_VERSION, retval ? "FAILED" : "OK"); } else { rtapi_print_msg(RTAPI_MSG_DBG, "ULAPI:%d init failed, realtime not running?" " global=%p rtapi=%p\n", rtapi_instance, global_data, rtapi_data); } } return retval; }