int hal_ring_detach(const char *name, ringbuffer_t *rbptr) { CHECK_HALDATA(); CHECK_STRLEN(name, HAL_NAME_LEN); CHECK_LOCK(HAL_LOCK_CONFIG); if ((rbptr == NULL) || (rbptr->magic != RINGBUFFER_MAGIC)) { HALERR("ring '%s': invalid ringbuffer", name); return -EINVAL; } // no mutex(es) held up to here { int retval __attribute__((cleanup(halpr_autorelease_mutex))); rtapi_mutex_get(&(hal_data->mutex)); ringheader_t *rhptr = rbptr->header; rhptr->refcount--; rbptr->magic = 0; // invalidate FIXME // unlocking happens automatically on scope exit } return 0; }
void timer_manager_t::register_timer(uint32_t interval_, const time_event_callback_t& callback_, bool persist_, time_t start_time_ ) { CHECK_LOCK(m_is_lock, m_mutex); time_t local_start_time = start_time_; if (!local_start_time) { local_start_time = get_cached_time_i().tv_sec; } time_event_t* time_event = new time_event_t( local_start_time, interval_, 0, local_start_time + interval_, callback_, persist_ ); if (NULL == time_event) { LOGWARN((TIMER_MANAGER_MODULE, "timer_manager_t::register_timer new time_event_t failed")); return; } //! yunjie: 这里不需要加锁, m_time_heap被初始化为线程安全的 register_timer_i(time_event); }
int hal_del_funct_from_thread(const char *funct_name, const char *thread_name) { hal_funct_t *funct; hal_list_t *list_root, *list_entry; hal_funct_entry_t *funct_entry; CHECK_HALDATA(); CHECK_LOCK(HAL_LOCK_CONFIG); CHECK_STR(funct_name); CHECK_STR(thread_name); HALDBG("removing function '%s' from thread '%s'", funct_name, thread_name); { hal_thread_t *thread __attribute__((cleanup(halpr_autorelease_mutex))); /* get mutex before accessing data structures */ rtapi_mutex_get(&(hal_data->mutex)); /* search function list for the function */ funct = halpr_find_funct_by_name(funct_name); if (funct == 0) { HALERR("function '%s' not found", funct_name); return -EINVAL; } /* found the function, is it in use? */ if (funct->users == 0) { HALERR("function '%s' is not in use", funct_name); return -EINVAL; } /* search thread list for thread_name */ thread = halpr_find_thread_by_name(thread_name); if (thread == 0) { /* thread not found */ HALERR("thread '%s' not found", thread_name); return -EINVAL; } /* ok, we have thread and function, does thread use funct? */ list_root = &(thread->funct_list); list_entry = list_next(list_root); while (1) { if (list_entry == list_root) { /* reached end of list, funct not found */ HALERR("thread '%s' doesn't use %s", thread_name, funct_name); return -EINVAL; } funct_entry = (hal_funct_entry_t *) list_entry; if (SHMPTR(funct_entry->funct_ptr) == funct) { /* this funct entry points to our funct, unlink */ list_remove_entry(list_entry); /* and delete it */ free_funct_entry_struct(funct_entry); /* done */ return 0; } /* try next one */ list_entry = list_next(list_entry); } } }
struct timeval timer_manager_t::get_cached_time() { CHECK_LOCK(m_is_lock, m_mutex); struct timeval ret = get_cached_time_i(); return ret; }
int io_multiplex_handler_t::remove_fd_from_epoll(fd_t fd_) { CHECK_LOCK(m_is_lock, m_mutex); int ret = remove_fd_from_epoll_i(fd_); return ret; }
int io_multiplex_handler_t::register_io_event(fd_t fd_, int event_type_flag_, callback_on_event_t event_cb_, void* cb_arg_, bool is_persist_) { CHECK_LOCK(m_is_lock, m_mutex); int ret = register_io_event_i(fd_, event_type_flag_, event_cb_, cb_arg_, is_persist_); return ret; }
void _dbg_spin_unlock(spinlock_t * lock, const char *base_file, int line_no) { CHECK_LOCK(lock); volatile unsigned int *a; mb(); a = __ldcw_align(lock); if (unlikely((*a != 0) && lock->babble)) { lock->babble--; pdc_printf( "%s:%d: spin_unlock(%s:%p) not locked\n", base_file, line_no, lock->module, lock); } *a = 1; mb(); }
void timer_manager_t::exec() { CHECK_LOCK(m_is_lock, m_mutex); if (!m_inited) { LOGWARN((TIMER_MANAGER_MODULE, "timer_manager_t::exec timer manager has not been inited.")); return; } time_t now = get_cached_time_i().tv_sec; timer_container_t::container_t tasks; uint32_t all_task_num = 0; //! yunjie: 用于在fetch_task过程中检测time event是否满足执行条件 struct timer_container_t::cond_checker_t checker(time_event_fetch_condition, (void*)&now, FETCH_BREAK); //! yunjie: 一次性抓取足够的需要被执行的time事件. m_time_heap.fetch_task(tasks, all_task_num, 0xffffffff, &checker); while (!tasks.empty()) { struct time_event_t* event = tasks.top(); event->exec(); if (event->persist) { event->last_exec_time = now; event->timestamp = now + event->interval; //! yunjie: 这时注册的event在该loop中将不会被检测. register_timer_i(event); } else { //! yunjie: release会对内部的async_method_t进行内存释放, 不是persist事件才能调用 event->release(); SAFE_DELETE(event); } tasks.pop(); } }
uint32_t timer_manager_t::size() { CHECK_LOCK(m_is_lock, m_mutex); return m_time_heap.size(); }
void timer_manager_t::flush_time() { CHECK_LOCK(m_is_lock, m_mutex); flush_time_i(); }
void timer_manager_t::clear() { CHECK_LOCK(m_is_lock, m_mutex); clear_i(); }
int io_multiplex_handler_t::wait_io_notification() { CHECK_LOCK(m_is_lock, m_mutex); if (0 == m_fd_set.size()) //! yunjie: 避免没有监听的fd也要system call陷入内核 { return 0; } int timeout = 50; //! yunjie: timeout暂时为50, 以后会进行优化 int res = ::epoll_wait(m_epoll_fd, &m_epoll_events[0], m_epoll_events.size(), timeout); //! yunjie: epoll_wait 非正常返回值处理. if (res == -1) { LOGWARN((IO_MULTIPLEX_MODULE, "io_multiplex_handler_t::wait_notification epoll_wait failed, res:[%d]", res)); return (0); } for (int i = 0; i < res; i++) { int what = m_epoll_events[i].events; //! yunjie: 当前循环epoll事件类型 fd_t fd = m_epoll_events[i].data.fd; //! yunjie: 当前循环epoll需要处理的fd if (fd < 0 || fd >= m_io_events.size()) //! yunjie: 非正常边界 { LOGWARN((IO_MULTIPLEX_MODULE, "io_multiplex_handler_t::wait_notification invaild file descriptor fd:[%d]", fd)); continue; } struct io_event_t& io_event = m_io_events[fd]; //! yunjie: 通过索引的方式取得该fd所对应的io_event_t对象 struct epoll_event epev = {0, {0}}; epev.data.fd = io_event.listen_fd; /* yunjie: EPOLLPRI - 表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来). * EPOLLERR - 表示对应的文件描述符发生错误. * EPOLLHUP - 表示对应的文件描述符被挂断. */ if (what & (EPOLLHUP|EPOLLERR)) //! yunjie: 对于该fd的错误现象进行处理, 进行回调. { //! yunjie: 从epoll中删除关联的socket /** yunjie: 删除操作交给使用者去决定 if (remove_fd_from_epoll_i(io_event.listen_fd) == -1) { LOGWARN((IO_MULTIPLEX_MODULE, "io_multiplex_handler_t::wait_notification remove_fd_from_epoll_i failed fd:%d.", io_event.listen_fd)); continue; } */ if (NULL != io_event.error_cb) { io_event.error_cb(fd, IO_ERROR_EVENT, io_event.error_cb_arg); } } else { int epoll_operate = 0; if (what & EPOLLIN) //! yunjie: 读事件 { if (NULL != io_event.read_cb) { io_event.read_cb(fd, IO_READ_EVENT, io_event.read_cb_arg); //! yunjie: 调用读回调 } //! yunjie: 如果读事件不是persist的, 需要进行epoll信息的修改 //! yunjie: 注意, 此时的io_event有可能已经被callback clear, 所以要来判断fd是否不为0 if (io_event.listen_fd && !io_event.read_persist) { //! yunjie: 如果有注册写事件, 那么不能直接删除epoll和socket的关联, 需要修改epoll信息, 否则就直接从epoll中删除socket的关联 if (NULL != io_event.write_cb) { epoll_operate = EPOLL_CTL_MOD; epev.events = EPOLLOUT; if (::epoll_ctl(m_epoll_fd, epoll_operate, io_event.listen_fd, &epev) == -1) { LOGWARN((IO_MULTIPLEX_MODULE, "io_multiplex_handler_t::wait_notification system call epoll_ctl failed fd:%d.", io_event.listen_fd)); continue; } } else { if (remove_fd_from_epoll_i(io_event.listen_fd) == -1) { LOGWARN((IO_MULTIPLEX_MODULE, "io_multiplex_handler_t::wait_notification remove_fd_from_epoll_i failed fd:%d.", io_event.listen_fd)); continue; } } io_event.read_cb = NULL; io_event.read_cb_arg = NULL; io_event.read_persist = false; } } if (what & EPOLLOUT) //! yunjie: 写事件 { if (NULL != io_event.write_cb) { io_event.write_cb(fd, IO_WRITE_EVENT, io_event.write_cb_arg); //! yunjie: 调用写回调 } //! yunjie: 如果写事件不是persist的, 需要进行epoll信息的修改 //! yunjie: 注意, 此时的io_event有可能已经被callback clear, 所以要来判断fd是否不为0 if (io_event.listen_fd && !io_event.write_persist) { //! yunjie: 如果有注册读事件, 那么不能直接删除epoll和socket的关联, 需要修改epoll信息, 否则就直接从epoll中删除socket的关联 if (NULL != io_event.read_cb) { epoll_operate = EPOLL_CTL_MOD; epev.events = EPOLLIN; if (::epoll_ctl(m_epoll_fd, epoll_operate, io_event.listen_fd, &epev) == -1) { LOGWARN((IO_MULTIPLEX_MODULE, "io_multiplex_handler_t::wait_notification system call epoll_ctl failed fd:%d.", io_event.listen_fd)); continue; } } else { if (remove_fd_from_epoll_i(io_event.listen_fd) == -1) { LOGWARN((IO_MULTIPLEX_MODULE, "io_multiplex_handler_t::wait_notification remove_fd_from_epoll_i failed fd:%d.", io_event.listen_fd)); continue; } } io_event.write_cb = NULL; io_event.write_cb_arg = NULL; io_event.write_persist = false; } } } } //! yunjie: 对m_epoll_events进行扩张, 这样的话可以尽可能通过一次epoll_wait我们能获得更多的fd, 减少内核线程的切换, 提高性能. int epoll_events_size = m_epoll_events.size(); if (res == epoll_events_size && epoll_events_size < EPOLL_EVENT_WAIT_NUM_MAX) { uint32_t new_size = epoll_events_size << 1; m_epoll_events.resize(new_size); //! yunjie: 成倍扩张, 由于初始值对齐到8(32), 所以最终极限扩张值必定是EPOLL_EVENT_WAIT_NUM_MAX(4096) LOGWARN((IO_MULTIPLEX_MODULE, "io_multiplex_handler_t::wait_io_notification m_epoll_events resize to %lu.", new_size)); } return res; }
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 hal_ring_delete(const char *name) { int retval; CHECK_HALDATA(); CHECK_STRLEN(name, HAL_NAME_LEN); CHECK_LOCK(HAL_LOCK_LOAD); { hal_ring_t *hrptr __attribute__((cleanup(halpr_autorelease_mutex))); rtapi_mutex_get(&(hal_data->mutex)); // ring must exist if ((hrptr = halpr_find_ring_by_name(name)) == NULL) { HALERR("ring '%s' not found", name); return -ENOENT; } ringheader_t *rhptr; int shmid = -1; if (hrptr->flags & ALLOC_HALMEM) { // ring exists as HAL memory. rhptr = SHMPTR(hrptr->ring_offset); } else { // ring exists as shm segment. Retrieve shared memory address. if ((shmid = rtapi_shmem_new_inst(hrptr->ring_shmkey, rtapi_instance, lib_module_id, 0 )) < 0) { if (shmid != -EEXIST) { HALERR("ring '%s': rtapi_shmem_new_inst() failed %d", name, shmid); return shmid; } } if ((retval = rtapi_shmem_getptr(shmid, (void **)&rhptr, 0))) { HALERR("ring '%s': rtapi_shmem_getptr %d failed %d", name, shmid, retval); return -ENOMEM; } } // assure attach/detach balance is zero: if (rhptr->refcount) { HALERR("ring '%s' still attached - refcount=%d", name, rhptr->refcount); return -EBUSY; } HALDBG("deleting ring '%s'", name); if (hrptr->flags & ALLOC_HALMEM) { ; // if there were a HAL memory free function, call it here } else { if ((retval = rtapi_shmem_delete(shmid, lib_module_id)) < 0) { HALERR("ring '%s': rtapi_shmem_delete(%d,%d) failed: %d", name, shmid, lib_module_id, retval); return retval; } } // search for the ring (again..) int *prev = &(hal_data->ring_list_ptr); int next = *prev; while (next != 0) { hrptr = SHMPTR(next); if (strcmp(hrptr->name, name) == 0) { // this is the right ring // unlink from list *prev = hrptr->next_ptr; // and delete it, linking it on the free list free_ring_struct(hrptr); return 0; } // no match, try the next one prev = &(hrptr->next_ptr); next = *prev; } HALERR("BUG: deleting ring '%s'; not found in ring_list?", name); return -ENOENT; } }
static int hal_export_xfunctfv(const hal_export_xfunct_args_t *xf, const char *fmt, va_list ap) { int *prev, next, cmp, sz; hal_funct_t *nf, *fptr; char name[HAL_NAME_LEN + 1]; CHECK_HALDATA(); CHECK_LOCK(HAL_LOCK_LOAD); sz = rtapi_vsnprintf(name, sizeof(name), fmt, ap); if(sz == -1 || sz > HAL_NAME_LEN) { HALERR("length %d invalid for name starting '%s'", sz, name); return -ENOMEM; } HALDBG("exporting function '%s' type %d", name, xf->type); { hal_comp_t *comp __attribute__((cleanup(halpr_autorelease_mutex))); /* get mutex before accessing shared data */ rtapi_mutex_get(&(hal_data->mutex)); comp = halpr_find_owning_comp(xf->owner_id); if (comp == 0) { /* bad comp_id */ HALERR("funct '%s': owning component %d not found", name, xf->owner_id); return -EINVAL; } if (comp->type == TYPE_USER) { /* not a realtime component */ HALERR("funct '%s': component %s/%d is not realtime (%d)", name, comp->name, comp->comp_id, comp->type); return -EINVAL; } bool legacy = (halpr_find_inst_by_id(xf->owner_id) == NULL); // instances may export functs post hal_ready if (legacy && (comp->state > COMP_INITIALIZING)) { HALERR("funct '%s': called after hal_ready", name); return -EINVAL; } /* allocate a new function structure */ nf = alloc_funct_struct(); if (nf == 0) NOMEM("function '%s'", name); /* initialize the structure */ nf->uses_fp = xf->uses_fp; nf->owner_id = xf->owner_id; nf->reentrant = xf->reentrant; nf->users = 0; nf->handle = rtapi_next_handle(); nf->arg = xf->arg; nf->type = xf->type; nf->funct.l = xf->funct.l; // a bit of a cheat really rtapi_snprintf(nf->name, sizeof(nf->name), "%s", name); /* search list for 'name' and insert new structure */ prev = &(hal_data->funct_list_ptr); next = *prev; while (1) { if (next == 0) { /* reached end of list, insert here */ nf->next_ptr = next; *prev = SHMOFF(nf); /* break out of loop and init the new function */ break; } fptr = SHMPTR(next); cmp = strcmp(fptr->name, nf->name); if (cmp > 0) { /* found the right place for it, insert here */ nf->next_ptr = next; *prev = SHMOFF(nf); /* break out of loop and init the new function */ break; } if (cmp == 0) { /* name already in list, can't insert */ free_funct_struct(nf); HALERR("duplicate function '%s'", name); return -EINVAL; } /* didn't find it yet, look at next one */ prev = &(fptr->next_ptr); next = *prev; } // at this point we have a new function and can // yield the mutex by scope exit } /* init time logging variables */ nf->runtime = 0; nf->maxtime = 0; nf->maxtime_increased = 0; /* at this point we have a new function and can yield the mutex */ rtapi_mutex_give(&(hal_data->mutex)); switch (xf->type) { case FS_LEGACY_THREADFUNC: case FS_XTHREADFUNC: /* create a pin with the function's runtime in it */ if (hal_pin_s32_newf(HAL_OUT, &(nf->runtime), xf->owner_id, "%s.time",name)) { HALERR("failed to create pin '%s.time'", name); return -EINVAL; } *(nf->runtime) = 0; /* note that failure to successfully create the following params does not cause the "export_funct()" call to fail - they are for debugging and testing use only */ /* create a parameter with the function's maximum runtime in it */ nf->maxtime = 0; hal_param_s32_newf(HAL_RW, &(nf->maxtime), xf->owner_id, "%s.tmax", name); /* create a parameter with the function's maximum runtime in it */ nf->maxtime_increased = 0; hal_param_bit_newf(HAL_RO, &(nf->maxtime_increased), xf->owner_id, "%s.tmax-inc", name); break; case FS_USERLAND: // no timing pins/params ; } return 0; }
int hal_add_funct_to_thread(const char *funct_name, const char *thread_name, int position) { hal_funct_t *funct; hal_list_t *list_root, *list_entry; int n; hal_funct_entry_t *funct_entry; CHECK_HALDATA(); CHECK_LOCK(HAL_LOCK_CONFIG); CHECK_STR(funct_name); CHECK_STR(thread_name); HALDBG("adding function '%s' to thread '%s'", funct_name, thread_name); { hal_thread_t *thread __attribute__((cleanup(halpr_autorelease_mutex))); /* get mutex before accessing data structures */ rtapi_mutex_get(&(hal_data->mutex)); /* make sure position is valid */ if (position == 0) { /* zero is not allowed */ HALERR("bad position: 0"); return -EINVAL; } /* search function list for the function */ funct = halpr_find_funct_by_name(funct_name); if (funct == 0) { HALERR("function '%s' not found", funct_name); return -EINVAL; } // type-check the functions which go onto threads switch (funct->type) { case FS_LEGACY_THREADFUNC: case FS_XTHREADFUNC: break; default: HALERR("cant add type %d function '%s' " "to a thread", funct->type, funct_name); return -EINVAL; } /* found the function, is it available? */ if ((funct->users > 0) && (funct->reentrant == 0)) { HALERR("function '%s' may only be added " "to one thread", funct_name); return -EINVAL; } /* search thread list for thread_name */ thread = halpr_find_thread_by_name(thread_name); if (thread == 0) { /* thread not found */ HALERR("thread '%s' not found", thread_name); return -EINVAL; } #if 0 /* ok, we have thread and function, are they compatible? */ if ((funct->uses_fp) && (!thread->uses_fp)) { HALERR("function '%s' needs FP", funct_name); return -EINVAL; } #endif /* find insertion point */ list_root = &(thread->funct_list); list_entry = list_root; n = 0; if (position > 0) { /* insertion is relative to start of list */ while (++n < position) { /* move further into list */ list_entry = list_next(list_entry); if (list_entry == list_root) { /* reached end of list */ HALERR("position '%d' is too high", position); return -EINVAL; } } } else { /* insertion is relative to end of list */ while (--n > position) { /* move further into list */ list_entry = list_prev(list_entry); if (list_entry == list_root) { /* reached end of list */ HALERR("position '%d' is too low", position); return -EINVAL; } } /* want to insert before list_entry, so back up one more step */ list_entry = list_prev(list_entry); } /* allocate a funct entry structure */ funct_entry = alloc_funct_entry_struct(); if (funct_entry == 0) NOMEM("thread->function link"); /* init struct contents */ funct_entry->funct_ptr = SHMOFF(funct); funct_entry->arg = funct->arg; funct_entry->funct.l = funct->funct.l; funct_entry->type = funct->type; /* add the entry to the list */ list_add_after((hal_list_t *) funct_entry, list_entry); /* update the function usage count */ funct->users++; } return 0; }