int hal_xinit(const int type, const int userarg1, const int userarg2, const hal_constructor_t ctor, const hal_destructor_t dtor, const char *name) { int comp_id, retval; rtapi_set_logtag("hal_lib"); CHECK_STRLEN(name, HAL_NAME_LEN); // sanity: these must have been inited before by the // respective rtapi.so/.ko module CHECK_NULL(rtapi_switch); if ((dtor != NULL) && (ctor == NULL)) { HALERR("component '%s': NULL constructor doesnt make" " sense with non-NULL destructor", name); return -EINVAL; } // RTAPI initialisation already done HALDBG("initializing component '%s' type=%d arg1=%d arg2=%d/0x%x", name, type, userarg1, userarg2, userarg2); if ((lib_module_id < 0) && (type != TYPE_HALLIB)) { // if hal_lib not inited yet, do so now - recurse #ifdef RTAPI retval = hal_xinit(TYPE_HALLIB, 0, 0, NULL, NULL, "hal_lib"); #else retval = hal_xinitf(TYPE_HALLIB, 0, 0, NULL, NULL, "hal_lib%ld", (long) getpid()); #endif if (retval < 0) return retval; } // tag message origin field since ulapi autoload re-tagged them temporarily rtapi_set_logtag("hal_lib"); /* copy name to local vars, truncating if needed */ char rtapi_name[RTAPI_NAME_LEN + 1]; char hal_name[HAL_NAME_LEN + 1]; rtapi_snprintf(hal_name, sizeof(hal_name), "%s", name); rtapi_snprintf(rtapi_name, RTAPI_NAME_LEN, "HAL_%s", hal_name); /* do RTAPI init */ comp_id = rtapi_init(rtapi_name); if (comp_id < 0) { HALERR("rtapi init(%s) failed", rtapi_name); return -EINVAL; } // recursing? init HAL shm if ((lib_module_id < 0) && (type == TYPE_HALLIB)) { // recursion case, we're initing hal_lib // get HAL shared memory from RTAPI int shm_id = rtapi_shmem_new(HAL_KEY, comp_id, global_data->hal_size); if (shm_id < 0) { HALERR("hal_lib:%d failed to allocate HAL shm %x, rc=%d", comp_id, HAL_KEY, shm_id); rtapi_exit(comp_id); return -EINVAL; } // retrieve address of HAL shared memory segment void *mem; retval = rtapi_shmem_getptr(shm_id, &mem, 0); if (retval < 0) { HALERR("hal_lib:%d failed to acquire HAL shm %x, id=%d rc=%d", comp_id, HAL_KEY, shm_id, retval); rtapi_exit(comp_id); return -EINVAL; } // set up internal pointers to shared mem and data structure hal_shmem_base = (char *) mem; hal_data = (hal_data_t *) mem; #ifdef RTAPI // only on RTAPI hal_lib initialization: // initialize up the HAL shm segment retval = init_hal_data(); if (retval) { HALERR("could not init HAL shared memory rc=%d", retval); rtapi_exit(lib_module_id); lib_module_id = -1; return -EINVAL; } retval = hal_proc_init(); if (retval) { HALERR("could not init /proc files"); rtapi_exit(lib_module_id); lib_module_id = -1; return -EINVAL; } #endif // record hal_lib comp_id lib_module_id = comp_id; // and the HAL shm segmed id lib_mem_id = shm_id; } // global_data MUST be at hand now: HAL_ASSERT(global_data != NULL); // paranoia HAL_ASSERT(hal_shmem_base != NULL); HAL_ASSERT(hal_data != NULL); HAL_ASSERT(lib_module_id > -1); HAL_ASSERT(lib_mem_id > -1); if (lib_module_id < 0) { HALERR("giving up"); return -EINVAL; } { hal_comp_t *comp __attribute__((cleanup(halpr_autorelease_mutex))); /* get mutex before manipulating the shared data */ rtapi_mutex_get(&(hal_data->mutex)); /* make sure name is unique in the system */ if (halpr_find_comp_by_name(hal_name) != 0) { /* a component with this name already exists */ HALERR("duplicate component name '%s'", hal_name); rtapi_exit(comp_id); return -EINVAL; } /* allocate a new component structure */ comp = halpr_alloc_comp_struct(); if (comp == 0) { HALERR("insufficient memory for component '%s'", hal_name); rtapi_exit(comp_id); return -ENOMEM; } /* initialize the comp structure */ comp->userarg1 = userarg1; comp->userarg2 = userarg2; comp->comp_id = comp_id; comp->type = type; comp->ctor = ctor; comp->dtor = dtor; #ifdef RTAPI comp->pid = 0; #else /* ULAPI */ // a remote component starts out disowned comp->pid = comp->type == TYPE_REMOTE ? 0 : getpid(); #endif comp->state = COMP_INITIALIZING; comp->last_update = 0; comp->last_bound = 0; comp->last_unbound = 0; comp->shmem_base = hal_shmem_base; comp->insmod_args = 0; rtapi_snprintf(comp->name, sizeof(comp->name), "%s", hal_name); /* insert new structure at head of list */ comp->next_ptr = hal_data->comp_list_ptr; hal_data->comp_list_ptr = SHMOFF(comp); } // scope exited - mutex released // finish hal_lib initialisation // in ULAPI this will happen after the recursion on hal_lib%d unwinds if (type == TYPE_HALLIB) { #ifdef RTAPI // only on RTAPI hal_lib initialization: // export the instantiation support userfuncts hal_export_xfunct_args_t ni = { .type = FS_USERLAND, .funct.u = create_instance, .arg = NULL, .owner_id = lib_module_id }; if ((retval = hal_export_xfunctf( &ni, "newinst")) < 0) return retval; hal_export_xfunct_args_t di = { .type = FS_USERLAND, .funct.u = delete_instance, .arg = NULL, .owner_id = lib_module_id }; if ((retval = hal_export_xfunctf( &di, "delinst")) < 0) return retval; #endif retval = hal_ready(lib_module_id); if (retval) HALERR("hal_ready(%d) failed rc=%d", lib_module_id, retval); else HALDBG("%s initialization complete", hal_name); return retval; } HALDBG("%s component '%s' id=%d initialized%s", (ctor != NULL) ? "instantiable" : "legacy", hal_name, comp_id, (dtor != NULL) ? ", has destructor" : ""); return comp_id; } int hal_exit(int comp_id) { int *prev, next, comptype; char name[HAL_NAME_LEN + 1]; CHECK_HALDATA(); HALDBG("removing component %d", comp_id); { hal_comp_t *comp __attribute__((cleanup(halpr_autorelease_mutex))); /* grab mutex before manipulating list */ rtapi_mutex_get(&(hal_data->mutex)); /* search component list for 'comp_id' */ prev = &(hal_data->comp_list_ptr); next = *prev; if (next == 0) { /* list is empty - should never happen, but... */ HALERR("no components defined"); return -EINVAL; } comp = SHMPTR(next); while (comp->comp_id != comp_id) { /* not a match, try the next one */ prev = &(comp->next_ptr); next = *prev; if (next == 0) { /* reached end of list without finding component */ HALERR("no such component with id %d", comp_id); return -EINVAL; } comp = SHMPTR(next); } // record type, since we're about to zap the comp in free_comp_struct() comptype = comp->type; /* save component name for later */ rtapi_snprintf(name, sizeof(name), "%s", comp->name); /* get rid of the component */ free_comp_struct(comp); // unlink the comp only now as free_comp_struct() must // determine ownership of pins/params/functs and this // requires access to the current comp, too // since this is all under lock it should not matter *prev = comp->next_ptr; // add it to free list comp->next_ptr = hal_data->comp_free_ptr; hal_data->comp_free_ptr = SHMOFF(comp); // scope exit - mutex released } // if unloading the hal_lib component, destroy HAL shm if (comptype == TYPE_HALLIB) { int retval; /* release RTAPI resources */ retval = rtapi_shmem_delete(lib_mem_id, comp_id); if (retval) { HALERR("rtapi_shmem_delete(%d,%d) failed: %d", lib_mem_id, comp_id, retval); } // HAL shm is history, take note ASAP lib_mem_id = -1; hal_shmem_base = NULL; hal_data = NULL;; retval = rtapi_exit(comp_id); if (retval) { HALERR("rtapi_exit(%d) failed: %d", lib_module_id, retval); } // the hal_lib RTAPI module is history, too // in theory we'd be back to square 1 lib_module_id = -1; } else { // the standard case rtapi_exit(comp_id); } //HALDBG("component '%s' id=%d removed", name, comp_id); return 0; }
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 hal_init_mode(const char *name, int type, int userarg1, int userarg2) { int comp_id; char rtapi_name[RTAPI_NAME_LEN + 1]; char hal_name[HAL_NAME_LEN + 1]; // tag message origin field rtapi_set_logtag("hal_lib"); if (name == 0) { hal_print_msg(RTAPI_MSG_ERR, "HAL: ERROR: no component name\n"); return -EINVAL; } if (strlen(name) > HAL_NAME_LEN) { hal_print_msg(RTAPI_MSG_ERR, "HAL: ERROR: component name '%s' is too long\n", name); return -EINVAL; } // rtapi initialisation already done // since this happens through the constructor hal_print_msg(RTAPI_MSG_DBG, "HAL: initializing component '%s' type=%d arg1=%d arg2=%d/0x%x\n", name, type, userarg1, userarg2, userarg2); /* copy name to local vars, truncating if needed */ rtapi_snprintf(rtapi_name, RTAPI_NAME_LEN, "HAL_%s", name); rtapi_snprintf(hal_name, sizeof(hal_name), "%s", name); /* do RTAPI init */ comp_id = rtapi_init(rtapi_name); if (comp_id < 0) { hal_print_msg(RTAPI_MSG_ERR, "HAL: ERROR: rtapi init failed\n"); return -EINVAL; } // tag message origin field since ulapi autoload re-tagged them rtapi_set_logtag("hal_lib"); #ifdef ULAPI hal_rtapi_attach(); #endif { hal_comp_t *comp __attribute__((cleanup(halpr_autorelease_mutex))); /* get mutex before manipulating the shared data */ rtapi_mutex_get(&(hal_data->mutex)); /* make sure name is unique in the system */ if (halpr_find_comp_by_name(hal_name) != 0) { /* a component with this name already exists */ hal_print_msg(RTAPI_MSG_ERR, "HAL: ERROR: duplicate component name '%s'\n", hal_name); rtapi_exit(comp_id); return -EINVAL; } /* allocate a new component structure */ comp = halpr_alloc_comp_struct(); if (comp == 0) { /* couldn't allocate structure */ hal_print_msg(RTAPI_MSG_ERR, "HAL: ERROR: insufficient memory for component '%s'\n", hal_name); rtapi_exit(comp_id); return -ENOMEM; } /* initialize the comp structure */ comp->userarg1 = userarg1; comp->userarg2 = userarg2; comp->comp_id = comp_id; comp->type = type; #ifdef RTAPI comp->pid = 0; //FIXME revisit this #else /* ULAPI */ // a remote component starts out disowned comp->pid = comp->type == TYPE_REMOTE ? 0 : getpid(); //FIXME revisit this #endif comp->state = COMP_INITIALIZING; comp->last_update = 0; comp->last_bound = 0; comp->last_unbound = 0; comp->shmem_base = hal_shmem_base; comp->insmod_args = 0; rtapi_snprintf(comp->name, sizeof(comp->name), "%s", hal_name); /* insert new structure at head of list */ comp->next_ptr = hal_data->comp_list_ptr; hal_data->comp_list_ptr = SHMOFF(comp); } // scope exited - mutex released /* done */ hal_print_msg(RTAPI_MSG_DBG, "HAL: component '%s' initialized, ID = %02d\n", hal_name, comp_id); return comp_id; }
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; }