/** * Creates a new process to be executed by one of the kernel pipelines. * The structure pointed by attr is defined in rtdal_process_attr. * * rtdal_process_new() configures the process parameters and loads it into the * pipeline. The process won't execute until a success call to rtdal_process_run() * is performed. * * The address pointed by arg will be passed to the process as a parameter. * * Notes: The shared library must conform with the rtdal_process_t requirements. * * @param attr Configures the process attributes * @param arg Argument to pass to the process each execution cycle * @return non-null value on success, zero on error */ r_proc_t rtdal_process_new(struct rtdal_process_attr *attr, void *arg) { hdebug("binary=%s, proc=%d, pos=%d, finish=0x%x, arg=0x%x\n",attr->binary_path,attr->pipeline_id, attr->exec_position,attr->finish_callback,arg); assert(context); RTDAL_ASSERT_PARAM_P(attr); RTDAL_ASSERT_PARAM_P(arg); pthread_mutex_lock(&context->mutex); int i=0; /* find empty space on process db */ for (i=0;i<MAX(rtdal_process);i++) { if (!context->processes[i].pid) break; } if (i == MAX(rtdal_process)) { RTDAL_SETERROR(RTDAL_ERROR_NOSPACE); goto out; } if (attr->process_group_id > MAX_PROCESS_GROUP_ID) { RTDAL_SETERROR(RTDAL_ERROR_NOSPACE); goto out; } if (attr->process_group_id < 0) { RTDAL_SETERROR(RTDAL_ERROR_INVAL); goto out; } pgroup_notified_failure[attr->process_group_id] = 0; memset(&context->processes[i],0,sizeof(rtdal_process_t)); context->processes[i].pid=i+1; hdebug("i=%d, pid=%d\n",context->processes[i].pid); memcpy(&context->processes[i].attributes, attr, sizeof(struct rtdal_process_attr)); context->processes[i].arg = arg; context->processes[i].finish_code = FINISH_OK; if (pipeline_add(&context->pipelines[attr->pipeline_id], &context->processes[i]) == -1) { goto out; } if (rtdal_process_launch(&context->processes[i])) { pipeline_remove(&context->pipelines[attr->pipeline_id], &context->processes[i]); goto out; } pthread_mutex_unlock(&context->mutex); return (r_proc_t) &context->processes[i]; out: pthread_mutex_unlock(&context->mutex); return NULL; }
/** * Removes the process proc from the pipeline pointed by obj. * @param obj Pointer to the pipeline object * @param proc Pointer to the process to remove * @return Zero on success, -1 on error */ int pipeline_remove(pipeline_t *obj, rtdal_process_t *proc) { hdebug("pipeid=%d, nof_process=%d, pid=%d, pid_pos=%d\n",obj->id,obj->nof_processes, proc->pid,proc->attributes.exec_position); RTDAL_ASSERT_PARAM(obj); RTDAL_ASSERT_PARAM(proc); rtdal_process_t *cur, *prev; prev = NULL; cur = obj->first_process; while(cur != proc && cur) { hdebug("pipeid=%d, prev=0x%x, cur=0x%x\n", obj->id, prev,cur); prev = cur; cur = cur->next; } if (!cur) { RTDAL_SETERROR(RTDAL_ERROR_NOTFOUND); return -1; } if (prev) { hdebug("pipeid=%d remove middle/end\n",obj->id); prev->next = cur->next; } else { hdebug("pipeid=%d remove first\n",obj->id); obj->first_process = cur->next; } obj->nof_processes--; proc->next = NULL; return 0; }
/** * Creates a new low-priority periodic function. If it succeeds, the function callback * will be called every period timeslots with low priority. * * @param callback Pointer to the periodic function * @param period Positive integer, in time slots * @return zero on success, -1 on error */ int rtdal_periodic_add(void (*callback)(void), int period) { assert(context); RTDAL_ASSERT_PARAM(callback); RTDAL_ASSERT_PARAM(period>0); pthread_mutex_lock(&context->mutex); int i; for (i=0;i<MAX(rtdal_periodic);i++) { if (!context->periodic[i].callback) break; } if (i == MAX(rtdal_periodic)) { RTDAL_SETERROR(RTDAL_ERROR_NOSPACE); pthread_mutex_unlock(&context->mutex); return -1; } context->periodic[i].counter = 0; context->periodic[i].period = period; context->periodic[i].callback = callback; pthread_mutex_unlock(&context->mutex); hdebug("i=%d, period=%d, callback=0x%x\n",i,period,callback); return 0; }
/** * Creates a new message spscq. * @param name Name of the new spscq interface * @param max_msg Positive integer. Maximum number of messages that can be inserted in the spscq * @param msg_sz Positive integer. Maximum message size * @return non-null value on success, zero on error */ r_itf_t rtdal_itfspscq_new(int max_msg, int max_msg_sz, int delay) { hdebug("max_msg=%d,max_msg_sz=%d\n",max_msg,max_msg_sz); assert(context); RTDAL_ASSERT_PARAM_P(max_msg>=0); RTDAL_ASSERT_PARAM_P(max_msg_sz>=0); int i; pthread_mutex_lock(&context->mutex); for (i=0;i<MAX(rtdal_itfspscq);i++) { if (!context->spscqs[i].parent.id) break; } if (i == MAX(rtdal_itfspscq)) { RTDAL_SETERROR(RTDAL_ERROR_NOTFOUND); return NULL; } hdebug("i=%d\n",i); context->spscqs[i].max_msg = max_msg; context->spscqs[i].max_msg_sz = max_msg_sz; context->spscqs[i].parent.delay = delay; context->spscqs[i].parent.id = i+1; if (rtdal_itfspscq_init(&context->spscqs[i])) { context->spscqs[i].parent.id = 0; pthread_mutex_unlock(&context->mutex); return NULL; } pthread_mutex_unlock(&context->mutex); return (r_itf_t) &context->spscqs[i]; }
/** * Acknowledges that the process group error notification has been processed, enabling another * future call to the finish_callback function. * \returns 0 on success, -1 on error */ int rtdal_process_group_notified(r_proc_t proc) { RTDAL_ASSERT_PARAM(proc); rtdal_process_t *obj = (rtdal_process_t*) proc; hdebug("pid=%d, running=%d\n",obj->pid,obj->runnable); if (obj->attributes.process_group_id < 0 || obj->attributes.process_group_id > MAX_PROCESS_GROUP_ID) { RTDAL_SETERROR(RTDAL_ERROR_INVAL); return -1; } pgroup_notified_failure[obj->attributes.process_group_id] = 0; return 0; }
int rtdal_itfspscq_push(r_itf_t obj, int len, int tstamp) { cast(obj,itf); if (spscq_is_full(itf)) { RTDAL_SETERROR(RTDAL_ERROR_NOSPACE); return 0; } itf->packets[itf->write].tstamp = tstamp+itf->parent.delay; itf->packets[itf->write].len = len; itf->packets[itf->write].valid = 1; itf->write += (itf->write+1 >= itf->max_msg) ? (1-itf->max_msg) : 1; qdebug("write=%d/%d, len=%d\n",itf->write,itf->max_msg,len); return 1; }
/** * Returns a handler to the first physical interface matching the id. * @param id Id of the physical interface * @return non-null value on success, zero on error */ r_itf_t rtdal_itfphysic_get_id(int id) { hdebug("id=%d\n",id); assert(context); RTDAL_ASSERT_PARAM_P(id); int i; for (i=0;i<MAX(rtdal_itfphysic);i++) { if (context->physic_itfs[i].parent.id == id) break; } hdebug("i=%d\n",i); if (i == MAX(rtdal_itfphysic)) { RTDAL_SETERROR(RTDAL_ERROR_NOTFOUND); return NULL; } return (r_itf_t) &context->physic_itfs[i]; }
/** * Returns a handler to the first physical interface matching the name. * @param name Name of the physical interface * @return non-null value on success, zero on error */ r_itf_t rtdal_itfphysic_get(string name) { hdebug("name=%s\n",name); assert(context); RTDAL_ASSERT_PARAM_P(name); int i; for (i=0;i<MAX(rtdal_itfphysic);i++) { if (!strcmp(context->physic_itfs[i].parent.name, name)) break; } hdebug("i=%d\n",i); if (i == MAX(rtdal_itfphysic)) { RTDAL_SETERROR(RTDAL_ERROR_NOTFOUND); return NULL; } return (r_itf_t) &context->physic_itfs[i]; }
int rtdal_itfspscq_request(r_itf_t obj, void **ptr) { cast(obj,itf); RTDAL_ASSERT_PARAM(ptr); *ptr = NULL; qdebug("write=%d, tstamp=%d\n",itf->write,itf->packets[itf->write].tstamp); if (spscq_is_full(itf)) { RTDAL_SETERROR(RTDAL_ERROR_NOSPACE); return 0; } qdebug("[ok] write=%d/%d, addr=0x%x\n",itf->write,itf->max_msg, itf->packets[itf->write].data); *ptr = itf->packets[itf->write].data; return 1; }
int rtdal_itfspscq_request(r_itf_t obj, void **ptr) { cast(obj,itf); RTDAL_ASSERT_PARAM(ptr); *ptr = NULL; qdebug("write=%d read=%d\n",itf->write,itf->read); if (spscq_is_full(itf)) { qdebug("[full] id=%d write=%d, valid=%d\n",itf->parent.id,itf->write,itf->packets[itf->write].valid); RTDAL_SETERROR(RTDAL_ERROR_NOSPACE); return 0; } qdebug("[ok] write=%d/%d\n",itf->write,itf->max_msg); *ptr = itf->packets[itf->write].data; return 1; }
int rtdal_itfspscq_send(r_itf_t obj, void* buffer, int len, int tstamp) { cast(obj,itf); RTDAL_ASSERT_PARAM(buffer); RTDAL_ASSERT_PARAM(len>=0); int n; void *ptr; if (len > itf->max_msg_sz) { RTDAL_SETERROR(RTDAL_ERROR_LARGE); return -1; } if ((n = rtdal_itfspscq_request(obj, &ptr)) != 1) { return n; } memcpy(ptr, buffer, (size_t) len); return rtdal_itfspscq_push(obj,ptr,len,tstamp); }
/** * Removes the function pointed by callback from the kernel periodic callback functions, * previously added with rtdal_periodic_add(). * * @param callback Pointer to the periodic function * @returns zero on success, -1 on error */ int rtdal_periodic_remove(void (*callback)(void)) { assert(context); RTDAL_ASSERT_PARAM(callback); int i; pthread_mutex_lock(&context->mutex); for (i=0;i<MAX(rtdal_periodic);i++) { if (context->periodic[i].callback == callback) break; } if (i == MAX(rtdal_periodic)) { RTDAL_SETERROR(RTDAL_ERROR_NOTFOUND); return -1; } context->periodic[i].counter = 0; context->periodic[i].period = 0; context->periodic[i].callback = NULL; pthread_mutex_unlock(&context->mutex); hdebug("i=%d\n",i); return 0; }
int rtdal_itfspscq_send(r_itf_t obj, void* buffer, int len) { cast(obj,itf); RTDAL_ASSERT_PARAM(buffer); RTDAL_ASSERT_PARAM(len>=0); int n; void *ptr; if (len > itf->max_msg_sz) { RTDAL_SETERROR(RTDAL_ERROR_LARGE); return -1; } hdebug("requesting pkt for 0x%x\n",obj); if ((n = rtdal_itfspscq_request(obj, &ptr)) != 1) { return n; } memcpy(ptr, buffer, (size_t) len); hdebug("put pkt for 0x%x pkt 0x%x\n",obj,ptr); return rtdal_itfspscq_push(obj,len,rtdal_time_slot()); }