static void cleanup_actions(void) { int retval; if (global_data) { if (global_data->rtapi_app_pid > 0) { kill(global_data->rtapi_app_pid, SIGTERM); syslog_async(LOG_INFO,"sent SIGTERM to rtapi (pid %d)\n", global_data->rtapi_app_pid); } // in case some process catches a leftover shm segment global_data->magic = GLOBAL_EXITED; global_data->rtapi_msgd_pid = 0; if (rtapi_msg_buffer.header != NULL) rtapi_msg_buffer.header->refcount--; retval = shm_common_detach(sizeof(global_data_t), global_data); if (retval < 0) { syslog_async(LOG_ERR,"shm_common_detach(global) failed: %s\n", strerror(-retval)); } else { shm_common_unlink(OS_KEY(GLOBAL_KEY, rtapi_instance)); syslog_async(LOG_DEBUG,"normal shutdown - global segment detached"); } global_data = NULL; } }
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; }
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 _rtapi_init(const char *modname) { int n, module_id; module_data *module; struct shm_status sm; int retval; /* say hello */ rtapi_print_msg(RTAPI_MSG_DBG, "ULAPI:%d initing module %s\n", rtapi_instance, modname); errno = 0; // if not done yet, attach global and rtapi_data segments now if (global_data == NULL) { sm.key = OS_KEY(GLOBAL_KEY, rtapi_instance); sm.size = sizeof(global_data_t); sm.flags = 0; if ((retval = shmdrv_attach(&sm, (void **)&global_data)) < 0) { rtapi_print_msg(RTAPI_MSG_ERR, "ULAPI:%d ERROR: can attach global segment: %d\n", rtapi_instance, retval); return -EINVAL; } sm.key = OS_KEY(RTAPI_KEY, rtapi_instance); sm.size = sizeof(rtapi_data_t); sm.flags = 0; if ((retval = shmdrv_attach(&sm, (void **)&rtapi_data)) < 0) { rtapi_print_msg(RTAPI_MSG_ERR, "ULAPI:%d ERROR: cant attach rtapi segment: %d\n", rtapi_instance, retval); return -EINVAL; } } // I consider this very dubious - there is no reason for ULAPI to start without // rtapi_data already being inited: -mah // 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, "ULAPI:%d ERROR: flavor mismatch %d vs %d\n", rtapi_instance, rtapi_data->thread_flavor_id, THREAD_FLAVOR_ID); return -EINVAL; } if (rtapi_data->serial != RTAPI_SERIAL) { /* mismatch - release master shared memory block */ rtapi_print_msg(RTAPI_MSG_ERR, "ULAPI:%d ERROR: serial mismatch %d vs %d\n", rtapi_instance, 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_SHMEMS; n++) { shmem_addr_array[n] = NULL; } /* get the mutex */ rtapi_mutex_get(&(rtapi_data->mutex)); /* find empty spot in module array */ n = 1; while ((n <= RTAPI_MAX_MODULES) && (module_array[n].state != NO_MODULE)) { n++; } if (n > RTAPI_MAX_MODULES) { /* no room */ rtapi_mutex_give(&(rtapi_data->mutex)); rtapi_print_msg(RTAPI_MSG_ERR, "ULAPI:%d ERROR: reached module limit %d\n", rtapi_instance,n); return -EMFILE; } /* we have space for the module */ module_id = n; module = &(module_array[n]); /* update module data */ module->state = USERSPACE; if (modname != NULL) { /* use name supplied by caller, truncating if needed */ rtapi_snprintf(module->name, RTAPI_NAME_LEN, "%s", modname); } else { /* make up a name */ rtapi_snprintf(module->name, RTAPI_NAME_LEN, "ULMOD%03d", module_id); } rtapi_data->ul_module_count++; rtapi_mutex_give(&(rtapi_data->mutex)); rtapi_print_msg(RTAPI_MSG_DBG, "ULAPI:%d module '%s' inited, ID = %02d\n", rtapi_instance,module->name, module_id); return module_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; }
void cleanup_module(void) { int n; struct shm_status sm; int retval; if (rtapi_data == NULL) { /* never got inited, nothing to do */ return; } #ifdef HAVE_RTAPI_MODULE_EXIT_HOOK _rtapi_module_exit_hook(); #endif /* grab the mutex */ rtapi_mutex_get(&(rtapi_data->mutex)); rtapi_print_msg(RTAPI_MSG_INFO, "RTAPI:%d exit\n", rtapi_instance); /* clean up leftover modules (start at 1, we don't use ID 0 */ for (n = 1; n <= RTAPI_MAX_MODULES; n++) { if (module_array[n].state == REALTIME) { rtapi_print_msg(RTAPI_MSG_WARN, "RTAPI: WARNING: module '%s' (ID: %02d) did not " "call rtapi_exit()\n", module_array[n].name, n); module_delete(n); } } /* cleaning up modules should clean up everything, if not there has probably been an unrecoverable internal error.... */ for (n = 1; n <= RTAPI_MAX_SHMEMS; n++) { if (shmem_array[n].rtusers > 0) { rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI: ERROR: shared memory block %02d not deleted\n", n); } } for (n = 1; n <= RTAPI_MAX_TASKS; n++) { if (task_array[n].state != EMPTY) { rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI: ERROR: task %02d not deleted\n", n); /* probably un-recoverable, but try anyway */ _rtapi_task_pause(n); /* rtapi_task_delete should not grab mutex */ task_array[n].state = DELETE_LOCKED; _rtapi_task_delete(n); } } if (rtapi_data->timer_running != 0) { #ifdef HAVE_RTAPI_MODULE_TIMER_STOP _rtapi_module_timer_stop(); #endif rtapi_data->timer_period = 0; timer_counts = 0; rtapi_data->timer_running = 0; max_delay = DEFAULT_MAX_DELAY; } rtapi_mutex_give(&(rtapi_data->mutex)); #ifdef CONFIG_PROC_FS proc_clean(); #endif sm.key = OS_KEY(RTAPI_KEY, rtapi_instance); sm.size = sizeof(rtapi_data_t); sm.flags = 0; if ((retval = shmdrv_detach(&sm)) < 0) { rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI:%d ERROR: detach rtapi returns %d\n", rtapi_instance, retval); } rtapi_data = NULL; global_data->rtapi_messages.refcount -= 1; // detach rtapi end 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, "RTAPI:%d ERROR: detach global returns %d\n", rtapi_instance, retval); } global_data = NULL; rtapi_print_msg(RTAPI_MSG_INFO, "RTAPI:%d Exit complete\n", rtapi_instance); return; }
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; }
int _rtapi_shmem_new_inst(int userkey, int instance, int module_id, unsigned long int size) { int n, retval; int shmem_id; shmem_data *shmem; struct shm_status sm; int key = OS_KEY(userkey, instance); /* key must be non-zero, and also cannot match the key that RTAPI uses */ if ((key == 0) || (key == OS_KEY(RTAPI_KEY, instance))) { rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI: ERROR: bad shmem key: %d\n", key); return -EINVAL; } /* get the mutex */ rtapi_mutex_get(&(rtapi_data->mutex)); /* validate module_id */ if ((module_id < 1) || (module_id > RTAPI_MAX_MODULES)) { rtapi_mutex_give(&(rtapi_data->mutex)); rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI: ERROR: bad module ID: %d\n", module_id); return -EINVAL; } if (module_array[module_id].state != MODULE_STATE) { rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI: ERROR: not a " OUR_API " module ID: %d\n", module_id); rtapi_mutex_give(&(rtapi_data->mutex)); return -EINVAL; } /* check if a block is already open for this key */ for (n = 1; n <= RTAPI_MAX_SHMEMS; n++) { if (shmem_array[n].key == key) { /* found a match */ shmem_id = n; shmem = &(shmem_array[n]); /* is it big enough? */ if (shmem->size < size) { rtapi_mutex_give(&(rtapi_data->mutex)); rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI: ERROR: shmem size mismatch\n"); return -EINVAL; } /* is this module already using it? */ if (rtapi_test_bit(module_id, shmem->bitmap)) { rtapi_mutex_give(&(rtapi_data->mutex)); rtapi_print_msg(RTAPI_MSG_WARN, "RTAPI: Warning: shmem already mapped\n"); return -EEXIST; } /* yes, has it been mapped into kernel space? */ #ifdef RTAPI if (shmem->rtusers == 0) { #endif /* no, map it and save the address */ sm.key = key; sm.size = size; sm.flags = 0; #ifdef ULAPI sm.driver_fd = shmdrv_driver_fd(); #endif retval = shmdrv_attach(&sm, &shmem_addr_array[shmem_id]); if (retval < 0) { rtapi_mutex_give(&(rtapi_data->mutex)); rtapi_print_msg(RTAPI_MSG_ERR, "shmdrv attached failed key=0x%x size=%ld\n", key, size); return retval; } if (shmem_addr_array[shmem_id] == NULL) { rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI: ERROR: failed to map shmem\n"); rtapi_mutex_give(&(rtapi_data->mutex)); #ifdef ULAPI check_memlock_limit("failed to map shmem"); #endif return -ENOMEM; } #ifdef RTAPI } #endif /* update usage data */ rtapi_set_bit(module_id, shmem->bitmap); #ifdef ULAPI shmem->ulusers++; #else /* RTAPI */ shmem->rtusers++; #endif /* RTAPI */ /* announce another user for this shmem */ rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: shmem %02d opened by module %02d\n", shmem_id, module_id); /* done */ rtapi_mutex_give(&(rtapi_data->mutex)); return shmem_id; } } /* find empty spot in shmem array */ n = 1; while ((n <= RTAPI_MAX_SHMEMS) && (shmem_array[n].key != 0)) { rtapi_print_msg(RTAPI_MSG_DBG, OUR_API ": shmem %d occupuied \n",n); n++; } if (n > RTAPI_MAX_SHMEMS) { /* no room */ rtapi_mutex_give(&(rtapi_data->mutex)); rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI: ERROR: reached shmem limit %d\n", n); return -EMFILE; } /* we have space for the block data */ rtapi_print_msg(RTAPI_MSG_DBG, OUR_API ": using new shmem %d \n",n); shmem_id = n; shmem = &(shmem_array[n]); /* get shared memory block from OS and save its address */ sm.key = key; sm.size = size; sm.flags = 0; #ifdef ULAPI sm.driver_fd = shmdrv_driver_fd(); #endif retval = shmdrv_create(&sm); if (retval < 0) { rtapi_mutex_give(&(rtapi_data->mutex)); rtapi_print_msg(RTAPI_MSG_ERR,"shmdrv create failed key=0x%x size=%ld\n", key, size); return retval; } retval = shmdrv_attach(&sm, &shmem_addr_array[shmem_id]); if (retval < 0) { rtapi_mutex_give(&(rtapi_data->mutex)); rtapi_print_msg(RTAPI_MSG_ERR,"shmdrv attached failed key=0x%x size=%ld\n", key, size); return retval; } if (shmem_addr_array[shmem_id] == NULL) { rtapi_mutex_give(&(rtapi_data->mutex)); rtapi_print_msg(RTAPI_MSG_ERR, "RTAPI: ERROR: could not create shmem %d\n", n); return -ENOMEM; } /* the block has been created, update data */ rtapi_set_bit(module_id, shmem->bitmap); shmem->key = key; #ifdef RTAPI shmem->rtusers = 1; shmem->ulusers = 0; #else /* ULAPI */ shmem->rtusers = 0; shmem->ulusers = 1; #endif /* ULAPI */ shmem->size = size; shmem->magic = SHMEM_MAGIC; shmem->instance = instance; rtapi_data->shmem_count++; /* zero the first word of the shmem area */ *((long int *) (shmem_addr_array[shmem_id])) = 0; /* announce the birth of a brand new baby shmem */ rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: shmem %02d created by module %02d, key: %d, size: %lu\n", shmem_id, module_id, key, size); /* and return the ID to the proud parent */ rtapi_mutex_give(&(rtapi_data->mutex)); return shmem_id; }
int hal_ring_new(const char *name, int size, int sp_size, int mode) { hal_ring_t *rbdesc; int *prev, next, cmp, retval; int ring_id; ringheader_t *rhptr; CHECK_HALDATA(); CHECK_STRLEN(name, HAL_NAME_LEN); CHECK_LOCK(HAL_LOCK_LOAD); { hal_ring_t *ptr __attribute__((cleanup(halpr_autorelease_mutex))); rtapi_mutex_get(&(hal_data->mutex)); // make sure no such ring name already exists if ((ptr = halpr_find_ring_by_name(name)) != 0) { HALERR("ring '%s' already exists", name); return -EEXIST; } // allocate a new ring id - needed since we dont track ring shm // segments in RTAPI if ((ring_id = next_ring_id()) < 0) { HALERR("cant allocate new ring id for '%s'", name); return -ENOMEM; } // allocate a new ring descriptor if ((rbdesc = alloc_ring_struct()) == 0) NOMEM("ring '%s'", name); rbdesc->handle = rtapi_next_handle(); rbdesc->flags = mode; rbdesc->ring_id = ring_id; // make total allocation fit ringheader, ringbuffer and scratchpad rbdesc->total_size = ring_memsize( rbdesc->flags, size, sp_size); if (rbdesc->flags & ALLOC_HALMEM) { void *ringmem = shmalloc_up(rbdesc->total_size); if (ringmem == NULL) NOMEM("ring '%s' size %d - insufficient HAL memory for ring", name,rbdesc->total_size); rbdesc->ring_offset = SHMOFF(ringmem); rhptr = ringmem; } else { // allocate shared memory segment for ring and init rbdesc->ring_shmkey = OS_KEY((RTAPI_RING_SHM_KEY + ring_id), rtapi_instance); int shmid; // allocate an RTAPI shm segment owned by HAL_LIB_xxx if ((shmid = rtapi_shmem_new(rbdesc->ring_shmkey, lib_module_id, rbdesc->total_size)) < 0) NOMEM("rtapi_shmem_new(0x%8.8x,%d) failed: %d", rbdesc->ring_shmkey, lib_module_id, rbdesc->total_size); // map the segment now so we can fill in the ringheader details if ((retval = rtapi_shmem_getptr(shmid, (void **)&rhptr, 0)) < 0) NOMEM("rtapi_shmem_getptr for %d failed %d", shmid, retval); } HALDBG("created ring '%s' in %s, total_size=%d", name, (rbdesc->flags & ALLOC_HALMEM) ? "halmem" : "shm", rbdesc->total_size); ringheader_init(rhptr, rbdesc->flags, size, sp_size); rhptr->refcount = 0; // on hal_ring_attach: increase; on hal_ring_detach: decrease rtapi_snprintf(rbdesc->name, sizeof(rbdesc->name), "%s", name); rbdesc->next_ptr = 0; // search list for 'name' and insert new structure prev = &(hal_data->ring_list_ptr); next = *prev; while (1) { if (next == 0) { /* reached end of list, insert here */ rbdesc->next_ptr = next; *prev = SHMOFF(rbdesc); return 0; } ptr = SHMPTR(next); cmp = strcmp(ptr->name, rbdesc->name); if (cmp > 0) { /* found the right place for it, insert here */ rbdesc->next_ptr = next; *prev = SHMOFF(rbdesc); return 0; } /* didn't find it yet, look at next one */ prev = &(ptr->next_ptr); next = *prev; } // automatic unlock by scope exit } }
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; }