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 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 shm_common_new(int key, int *size, int instance, void **shmptr, int create) { struct shm_status sm; int retval; int is_new = 0; if (shmdrv_loaded) { // use shmdrv kernel driver sm.driver_fd = shmdrv_driver_fd(); sm.key = key; sm.size = (size == NULL? 0: *size); sm.flags = 0; retval = shmdrv_status(&sm); // check if exists if (retval && !create) { // didnt exist, but just attach requested, so fail close(sm.driver_fd); return -ENOENT; } if (retval) { // didnt exist, so create retval = shmdrv_create(&sm); if (retval < 0) { return retval; } is_new = 1; } // now attach retval = shmdrv_attach(&sm, shmptr); if (retval < 0) { close(sm.driver_fd); return retval; } // if size was passed in as 0 (attach), fill in actual size if (size && (*size == 0)) *size = sm.size; close(sm.driver_fd); return is_new; } else { // use POSIX shared memory int shmfd, mmap_size; mode_t old_umask; char segment_name[LINELEN]; if ((size == 0) || (*size == 0)) mmap_size = 0; else mmap_size = *size; sprintf(segment_name, SHM_FMT, instance, key); old_umask = umask(0); //S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); if (create && ((shmfd = shm_open(segment_name, (O_CREAT | O_EXCL | O_RDWR), (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP))) > 0)) { // initial creation if (fchown(shmfd, getuid(),getgid())) perror("fchown"); if (ftruncate(shmfd, mmap_size)) perror("ftruncate"); is_new = 1; } else if((shmfd = shm_open(segment_name, O_RDWR, (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP))) < 0) { // just attach, and that failed: umask(old_umask); return -errno; } else { // shmfd open if (mmap_size == 0) { struct stat st; if (fstat(shmfd, &st)) { perror("fstat"); return -errno; } mmap_size = st.st_size; } } if((*shmptr = mmap(0, mmap_size, (PROT_READ | PROT_WRITE), MAP_SHARED, shmfd, 0)) == MAP_FAILED) { perror("shm_common_new:mmap"); close(shmfd); umask(old_umask); return -errno; } if (size) // return actual shm size as determined in attach *size = mmap_size; umask(old_umask); close(shmfd); return is_new; } }