VCOS_STATUS_T vcos_init(void) { VCOS_STATUS_T st = VCOS_SUCCESS; #ifdef HAVE_MTRACE // enable glibc memory debugging, if the environment // variable MALLOC_TRACE names a valid file. mtrace(); #endif vcos_mutex_create(&lock, "global_lock"); vcos_demand(pthread_key_create(&_vcos_thread_current_key, NULL) == 0); /* Initialise a VCOS wrapper for the thread which called vcos_init. */ vcos_semaphore_create(&vcos_thread_main.suspend, NULL, 0); vcos_thread_main.thread = pthread_self(); pthread_setspecific(_vcos_thread_current_key, &vcos_thread_main); st = vcos_msgq_init(); vcos_assert(st == VCOS_SUCCESS); vcos_logging_init(); return st; }
/*********************************************************** * Name: os_cond_wait * * Arguments: OS_COND_T *cond, * OS_SEMAPHORE_T *semaphore * * Description: Routine to wait for a condition variable * to be signalled. Semaphore is released * while waiting. The same semaphore must * always be used. * * Returns: int32_t - success == 0 * ***********************************************************/ int32_t os_cond_wait( OS_COND_T *cond, OS_SEMAPHORE_T *semaphore ) { int32_t success = -1; if (cond && semaphore) { COND_WAITER_T w; COND_WAITER_T *p, **prev; // Check the API is being followed os_assert((*cond)->semaphore == semaphore && os_semaphore_obtained(semaphore)); // Fill in a new waiter structure allocated on our stack w.next = NULL; vcos_demand(vcos_event_create(&w.latch, NULL) == VCOS_SUCCESS); // Add it to the end of the condvar's wait queue (we wake first come, first served) prev = &(*cond)->waiters; p = (*cond)->waiters; while (p) prev = &p->next, p = p->next; *prev = &w; // Ready to go to sleep now success = os_semaphore_release(semaphore); os_assert(success == 0); vcos_event_wait(&w.latch); success = os_semaphore_obtain(semaphore); os_assert(success == 0); } return success; }
void vchiq_release_message(VCHIQ_STATE_T *state, VCHIQ_HEADER_T *header) { SLOT_T *s = (SLOT_T *) header; VCHIQ_WRAPPER_T *st = (VCHIQ_WRAPPER_T *) s->hdr.u.slot; int slot = s-st->slot; vcos_demand(slot < SLOT_NUM); st->slot_free |= 1<<slot; }
void vchiq_wrapper_callback(void *callback_param, VCHI_CALLBACK_REASON_T reason, void *handle) { VCHIQ_WRAPPER_T *st = (VCHIQ_WRAPPER_T *) callback_param; switch(reason) { case VCHI_CALLBACK_MSG_AVAILABLE: { void *data; uint32_t size; int count = 0; while(vchi_msg_peek(st->vchi_handle, &data, &size, 0) == 0) { SLOT_T *s; int slot = 0; vcos_demand(st->slot_free != 0); while(!((1<<slot) & st->slot_free)) slot++; s = st->slot+slot; st->slot_free &= ~(1<<slot); s->hdr.u.slot = (VCHIQ_SLOT_T *) st; // store this away so we can release the slot properly s->hdr.size = size; vcos_demand(s->hdr.size <= SLOT_SIZE); memcpy(s->data, data, s->hdr.size); vchi_msg_remove(st->vchi_handle); st->callback(VCHIQ_MESSAGE_AVAILABLE, (VCHIQ_HEADER_T *) s, st->userdata, NULL); } break; } case VCHI_CALLBACK_BULK_RECEIVED: { // this doesn't seem to be used, but leave it in anyway st->callback(VCHIQ_BULK_RECEIVE_DONE, NULL, st->userdata, NULL); break; } } }
void vchiq_queue_message(VCHIQ_STATE_T *state, int fourcc, const VCHIQ_ELEMENT_T *elements, int count) { VCHIQ_WRAPPER_T *st = wrapper_list; VCHI_MSG_VECTOR_EX_T vec[4]; int i; while(st != NULL && (st->state != state || st->fourcc != fourcc)) st = st->next; vcos_demand(st != NULL); vcos_demand(count <= 4); for(i=0; i<count; i++) { vec[i].type = VCHI_VEC_POINTER; vec[i].u.ptr.vec_base = elements[i].data; vec[i].u.ptr.vec_len = elements[i].size; } vchi_msg_queuev_ex(st->vchi_handle, vec, count, VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE, NULL); }
// if handle==MEM_HANDLE_INVALID: data is a pointer, size is length // if handle!=MEM_HANDLE_INVALID: data is int, offset from handle base, size is length void vchiq_queue_bulk_transmit(VCHIQ_STATE_T *state, int fourcc, VCHI_MEM_HANDLE_T handle, const void *data, int size, void *userdata) { VCHIQ_WRAPPER_T *st = wrapper_list; while(st != NULL && (st->state != state || st->fourcc != fourcc)) st = st->next; vcos_demand(st != NULL); if(handle == MEM_HANDLE_INVALID) vchi_bulk_queue_transmit(st->vchi_handle, data, size, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); else vchi_bulk_queue_transmit_reloc(st->vchi_handle, handle, (uint32_t) data, size, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); }
// if handle==MEM_HANDLE_INVALID: data is a pointer, size is length // if handle!=MEM_HANDLE_INVALID: data is int, offset from handle base, size is length void vchiq_queue_bulk_receive(VCHIQ_STATE_T *state, int fourcc, VCHI_MEM_HANDLE_T handle, void *data, int size, void *userdata) { VCHIQ_WRAPPER_T *st = wrapper_list; while(st != NULL && (st->state != state || st->fourcc != fourcc)) st = st->next; vcos_demand(st != NULL); if(handle == MEM_HANDLE_INVALID) vchi_bulk_queue_receive(st->vchi_handle, data, size, VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE, NULL); else vchi_bulk_queue_receive_reloc(st->vchi_handle, handle, (uint32_t) data, size, VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE, NULL); st->callback(VCHIQ_BULK_RECEIVE_DONE, NULL, st->userdata, NULL); }
/* OMX_Init */ OMX_ERRORTYPE OMX_APIENTRY OMX_Init(void) { VCOS_STATUS_T status; OMX_ERRORTYPE err = OMX_ErrorNone; status = vcos_once(&once, initOnce); vcos_demand(status == VCOS_SUCCESS); vcos_mutex_lock(&lock); if(coreInit == 0) { // we need to connect via an ILCS connection to VideoCore VCHI_INSTANCE_T initialise_instance; VCHI_CONNECTION_T *connection; ILCS_CONFIG_T config; vc_host_get_vchi_state(&initialise_instance, &connection); vcilcs_config(&config); ilcs_service = ilcs_init((VCHIQ_INSTANCE_T) initialise_instance, (void **) &connection, &config, 0); if(ilcs_service == NULL) { err = OMX_ErrorHardware; goto end; } coreInit = 1; } else coreInit++; end: vcos_mutex_unlock(&lock); return err; }
/** Render text. * * FIXME: Not at all optimal - re-renders each time. * FIXME: Not UTF-8 aware * FIXME: better caching */ VCOS_STATUS_T gx_priv_render_text( GX_DISPLAY_T *disp, GRAPHICS_RESOURCE_HANDLE res, uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint32_t fg_colour, uint32_t bg_colour, const char *text, uint32_t text_length, uint32_t text_size ) { VGfloat vg_colour[4]; VGFT_FONT_T *font; VGPaint fg; GX_CLIENT_STATE_T save; VCOS_STATUS_T status = VCOS_SUCCESS; int clip = 1; vcos_demand(inited); // has gx_font_init() been called? gx_priv_save(&save, res); if (width == GRAPHICS_RESOURCE_WIDTH && height == GRAPHICS_RESOURCE_HEIGHT) { clip = 0; } width = (width == GRAPHICS_RESOURCE_WIDTH) ? res->width : width; height = (height == GRAPHICS_RESOURCE_HEIGHT) ? res->height : height; font = find_font(text, text_size); if (!font) { status = VCOS_ENOMEM; goto finish; } // setup the clipping rectangle if (clip) { VGint coords[] = {x,y,width,height}; vgSeti(VG_SCISSORING, VG_TRUE); vgSetiv(VG_SCISSOR_RECTS, 4, coords); } // setup the background colour if needed if (bg_colour != GRAPHICS_TRANSPARENT_COLOUR) { int err; VGfloat rendered_w, rendered_h; VGfloat vg_bg_colour[4]; // setup the background colour... gx_priv_colour_to_paint(bg_colour, vg_bg_colour); vgSetfv(VG_CLEAR_COLOR, 4, vg_bg_colour); // fill in a rectangle... vgft_get_text_extents(font, text, text_length, (VGfloat)x, (VGfloat)y, &rendered_w, &rendered_h); if ( ( 0 < (VGint)rendered_w ) && ( 0 < (VGint)rendered_h ) ) { vgClear(x, y, (VGint)rendered_w, (VGint)rendered_h); err = vgGetError(); if (err) { GX_LOG("Error %d clearing bg text %d %d %g %g", err, x, y, rendered_w, rendered_h); vcos_assert(0); } // if } // if } // if // setup the foreground colour fg = vgCreatePaint(); if (!fg) { status = VCOS_ENOMEM; goto finish; } // draw the foreground text vgSetParameteri(fg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); gx_priv_colour_to_paint(fg_colour, vg_colour); vgSetParameterfv(fg, VG_PAINT_COLOR, 4, vg_colour); vgSetPaint(fg, VG_FILL_PATH); vgft_font_draw(font, (VGfloat)x, (VGfloat)y, text, text_length, VG_FILL_PATH); vgDestroyPaint(fg); vcos_assert(vgGetError() == 0); vgSeti(VG_SCISSORING, VG_FALSE); finish: gx_priv_restore(&save); return status; }
VCOS_STATUS_T vcos_thread_create(VCOS_THREAD_T *thread, const char *name, VCOS_THREAD_ATTR_T *attrs, VCOS_THREAD_ENTRY_FN_T entry, void *arg) { VCOS_STATUS_T st; pthread_attr_t pt_attrs; VCOS_THREAD_ATTR_T *local_attrs = attrs ? attrs : &default_attrs; int rc = pthread_attr_init(&pt_attrs); if (rc < 0) return VCOS_ENOMEM; st = vcos_semaphore_create(&thread->suspend, NULL, 0); if (st != VCOS_SUCCESS) { pthread_attr_destroy(&pt_attrs); return st; } thread->task_timer.pfn = NULL; /* Not initialised */ pthread_attr_setstacksize(&pt_attrs, local_attrs->ta_stacksz); #if VCOS_CAN_SET_STACK_ADDR if (local_attrs->ta_stackaddr) { pthread_attr_setstackaddr(&pt_attrs, local_attrs->ta_stackaddr); } #else vcos_demand(local_attrs->ta_stackaddr == 0); #endif /* pthread_attr_setpriority(&pt_attrs, local_attrs->ta_priority); */ vcos_assert(local_attrs->ta_stackaddr == 0); /* Not possible */ thread->entry = entry; thread->arg = arg; thread->legacy = local_attrs->legacy; if (name) { strncpy(thread->name, name, sizeof(thread->name)-1); thread->name[sizeof(thread->name)-1] = '\0'; } else { thread->name[0] = '\0'; } rc = pthread_create(&thread->thread, &pt_attrs, vcos_thread_entry, thread); pthread_attr_destroy(&pt_attrs); memset(thread->at_exit, 0, sizeof(thread->at_exit)); if (rc < 0) { vcos_semaphore_delete(&thread->suspend); return VCOS_ENOMEM; } else { return VCOS_SUCCESS; } }
void os_cond_init(void) { vcos_assert(vcos_cv_inited++ == 0); vcos_demand(vcos_mutex_create(&cond_latch,NULL) == VCOS_SUCCESS); }
/* Atomic creation of lock protecting shared state */ static void initOnce(void) { VCOS_STATUS_T status; status = vcos_mutex_create(&lock, VCOS_FUNCTION); vcos_demand(status == VCOS_SUCCESS); }
VCOS_STATUS_T vcos_generic_blockpool_init(VCOS_BLOCKPOOL_T *pool, VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size, void *start, VCOS_UNSIGNED pool_size, VCOS_UNSIGNED align, VCOS_UNSIGNED flags, const char *name) { VCOS_STATUS_T status = VCOS_SUCCESS; vcos_unused(name); vcos_unused(flags); vcos_log_trace( "%s: pool %p num_blocks %d block_size %d start %p pool_size %d name %p", VCOS_FUNCTION, pool, num_blocks, block_size, start, pool_size, name); vcos_demand(pool); vcos_demand(start); vcos_assert((block_size > 0)); vcos_assert(num_blocks > 0); if (! align) align = VCOS_BLOCKPOOL_ALIGN_DEFAULT; if (align & 0x3) { vcos_log_error("%s: invalid alignment %d", VCOS_FUNCTION, align); return VCOS_EINVAL; } if (VCOS_BLOCKPOOL_SIZE(num_blocks, block_size, align) > pool_size) { vcos_log_error("%s: Pool is too small" \ " num_blocks %d block_size %d align %d" " pool_size %d required size %d", VCOS_FUNCTION, num_blocks, block_size, align, pool_size, (int) VCOS_BLOCKPOOL_SIZE(num_blocks, block_size, align)); return VCOS_ENOMEM; } status = vcos_mutex_create(&pool->mutex, "vcos blockpool mutex"); if (status != VCOS_SUCCESS) return status; pool->block_data_size = block_size; /* TODO - create flag that if set forces the header to be in its own cache * line */ pool->block_size = VCOS_BLOCKPOOL_ROUND_UP(pool->block_data_size + (align >= 4096 ? 32 : 0) + sizeof(VCOS_BLOCKPOOL_HEADER_T), align); pool->magic = VCOS_BLOCKPOOL_MAGIC; pool->num_subpools = 1; pool->num_extension_blocks = 0; pool->align = align; memset(pool->subpools, 0, sizeof(pool->subpools)); vcos_generic_blockpool_subpool_init(pool, &pool->subpools[0], start, pool_size, num_blocks, align, VCOS_BLOCKPOOL_SUBPOOL_FLAG_NONE); return status; }