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 init_module(void) { int n; struct shm_status sm; int retval; rtapi_switch = rtapi_get_handle(); // first thing: attach global_data sm.key = OS_KEY(GLOBAL_KEY, rtapi_instance); sm.size = 0; sm.flags = 0; if ((retval = shmdrv_attach(&sm, (void **)&global_data)) < 0) { // cant use the message ringbuffer just yet printk("RTAPI:%d ERROR: can attach global segment: %d\n", rtapi_instance, retval); return -EINVAL; } // fail immediately if the global segment isnt in shape yet // this catches https://github.com/zultron/linuxcnc/issues/49 early if (global_data->magic != GLOBAL_READY) { printk("RTAPI:%d ERROR: bad global magic: 0x%x\n", rtapi_instance,global_data->magic); // TBD: remove once cause identified printk("halsize=%d\n", global_data->hal_size); printk("msgd pid=%d\n", global_data->rtapi_msgd_pid); printk("magic=%x\n", global_data->magic); printk("flavor=%d\n", global_data->rtapi_thread_flavor); // fail the insmod return -EINVAL; } // say hello - this now goes through the message ringbuffer rtapi_print_msg(RTAPI_MSG_INFO, "RTAPI:%d %s %s init\n", rtapi_instance, rtapi_get_handle()->thread_flavor_name, GIT_VERSION); sm.key = OS_KEY(RTAPI_KEY, rtapi_instance); sm.size = sizeof(rtapi_data_t); sm.flags = 0; if ((retval = shmdrv_create(&sm)) < 0) { rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI:%d ERROR: can create rtapi segment: %d\n", rtapi_instance, retval); return -EINVAL; } if ((retval = shmdrv_attach(&sm, (void **)&rtapi_data)) < 0) { rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI:%d ERROR: cant attach rtapi segment: %d\n", rtapi_instance, retval); return -EINVAL; } // make error ringbuffer accessible within RTAPI ringbuffer_init(&global_data->rtapi_messages, &rtapi_message_buffer); global_data->rtapi_messages.refcount += 1; // rtapi is 'attached' // tag messages originating from RT proper rtapi_set_logtag("rt"); /* this will take care of any threads flavor hook */ init_rtapi_data(rtapi_data); /* check flavor and serial codes */ if (rtapi_data->thread_flavor_id != THREAD_FLAVOR_ID) { /* mismatch - release master shared memory block */ rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI: ERROR: flavor mismatch %d vs %d\n", rtapi_data->thread_flavor_id, THREAD_FLAVOR_ID); sm.key = OS_KEY(RTAPI_KEY, rtapi_instance); sm.size = sizeof(global_data_t); sm.flags = 0; if ((retval = shmdrv_detach(&sm)) < 0) { rtapi_print_msg(RTAPI_MSG_ERR, "INSTANCE:%d ERROR: shmdrv_detach() returns %d\n", rtapi_instance, retval); } sm.key = OS_KEY(GLOBAL_KEY, rtapi_instance); sm.size = sizeof(global_data_t); sm.flags = 0; if ((retval = shmdrv_detach(&sm)) < 0) { rtapi_print_msg(RTAPI_MSG_ERR, "INSTANCE:%d ERROR: shmdrv_detach() returns %d\n", rtapi_instance, retval); } return -EINVAL; } if (rtapi_data->serial != RTAPI_SERIAL) { /* mismatch - release master shared memory block */ rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI: ERROR: serial mismatch '%d' vs '%d'\n", rtapi_data->serial, RTAPI_SERIAL); return -EINVAL; } /* set up local pointers to global data */ module_array = rtapi_data->module_array; task_array = rtapi_data->task_array; shmem_array = rtapi_data->shmem_array; /* perform local init */ for (n = 0; n <= RTAPI_MAX_TASKS; n++) { ostask_array[n] = NULL; } for (n = 0; n <= RTAPI_MAX_SHMEMS; n++) { shmem_addr_array[n] = NULL; } rtapi_data->timer_running = 0; rtapi_data->timer_period = 0; max_delay = DEFAULT_MAX_DELAY; #ifdef RT_LINUX_USE_FPU rt_linux_use_fpu(1); #endif #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) /* on SMP machines, we want to put RT code on the last CPU */ n = NR_CPUS-1; while ( ! cpu_online(n) ) { n--; } rtapi_data->rt_cpu = n; #else /* old kernel, the SMP hooks aren't available, so use CPU 0 */ rtapi_data->rt_cpu = 0; #endif #ifdef CONFIG_PROC_FS /* set up /proc/rtapi */ if (proc_init() != 0) { rtapi_print_msg(RTAPI_MSG_WARN, "RTAPI: WARNING: Could not activate /proc entries\n"); proc_clean(); } #endif #ifdef HAVE_RTAPI_MODULE_INIT_HOOK _rtapi_module_init_hook(); #endif /* done */ rtapi_print_msg(RTAPI_MSG_INFO, "RTAPI:%d Init complete\n", rtapi_instance); return 0; }
int rtapi_app_main(void) { int retval; void *mem; rtapi_switch = rtapi_get_handle(); hal_print_msg(RTAPI_MSG_DBG, "HAL_LIB:%d loading RT support gd=%pp\n",rtapi_instance,global_data); /* do RTAPI init */ lib_module_id = rtapi_init("HAL_LIB"); if (lib_module_id < 0) { hal_print_msg(RTAPI_MSG_ERR, "HAL_LIB:%d ERROR: rtapi init failed\n", rtapi_instance); return -EINVAL; } // paranoia if (global_data == NULL) { hal_print_msg(RTAPI_MSG_ERR, "HAL_LIB:%d ERROR: global_data == NULL\n", rtapi_instance); return -EINVAL; } /* get HAL shared memory block from RTAPI */ lib_mem_id = rtapi_shmem_new(HAL_KEY, lib_module_id, global_data->hal_size); if (lib_mem_id < 0) { hal_print_msg(RTAPI_MSG_ERR, "HAL_LIB:%d ERROR: could not open shared memory\n", rtapi_instance); rtapi_exit(lib_module_id); return -EINVAL; } /* get address of shared memory area */ retval = rtapi_shmem_getptr(lib_mem_id, &mem, 0); if (retval < 0) { hal_print_msg(RTAPI_MSG_ERR, "HAL_LIB:%d ERROR: could not access shared memory\n", rtapi_instance); rtapi_exit(lib_module_id); return -EINVAL; } /* set up internal pointers to shared mem and data structure */ hal_shmem_base = (char *) mem; hal_data = (hal_data_t *) mem; /* perform a global init if needed */ retval = init_hal_data(); if ( retval ) { hal_print_msg(RTAPI_MSG_ERR, "HAL_LIB:%d ERROR: could not init shared memory\n", rtapi_instance); rtapi_exit(lib_module_id); return -EINVAL; } retval = hal_proc_init(); if ( retval ) { hal_print_msg(RTAPI_MSG_ERR, "HAL_LIB: ERROR:%d could not init /proc files\n", rtapi_instance); rtapi_exit(lib_module_id); return -EINVAL; } /* done */ hal_print_msg(RTAPI_MSG_DBG, "HAL_LIB:%d kernel lib installed successfully\n", rtapi_instance); return 0; }
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; }