void nx_window_delete(nx_window *self) { if(nx_thread_is_running(self->thread)) nx_window_close(self); nx_thread_end(self->thread); nx_event_source_delete(self->event_source); nx_free(self->title); nx_free(self); }
struct nx_thread_t* nx_thread_begin(nx_thread_proc proc, void *param) { struct nx_thread_t *thread; pthread_attr_t attribute; if(!proc) return 0; thread = nx_malloc(sizeof(nx_thread)); thread->proc = proc; thread->param = param; thread->time_to_quit = nxfalse; thread->is_running = nxfalse; pthread_attr_init(&attribute); if(pthread_attr_setdetachstate(&attribute, PTHREAD_CREATE_JOINABLE) == 0) { if(pthread_create(&thread->handle, &attribute, (void *(*) (void *))&_nx_thread_exec, thread) == 0) return thread; } nx_free(thread); return 0; }
void nx_thread_end(nx_thread *self) { if(nx_thread_is_running(self)) nx_thread_quit(self); nx_thread_wait(self,0); nx_free(self); }
/* This is where most of the magic happens. This function gets called * every millisecond to handle scheduling decisions. */ static void scheduler_cb(void) { U32 time = nx_systick_get_ms(); bool need_reschedule = FALSE; /* Security mechanism: in case the system crashes, as long as the * scheduler is still running, the brick can be powered off. */ if (nx_avr_get_button() == BUTTON_CANCEL) nx_core_halt(); /* If the scheduler state is locked, nothing can be done. */ if (sched_lock > 0) return; sched_lock = 1; /* Process pending commands, if any */ if (task_command != CMD_NONE) { switch (task_command) { case CMD_YIELD: need_reschedule = TRUE; break; case CMD_DIE: destroy_running_task(); need_reschedule = TRUE; break; default: break; } task_command = CMD_NONE; nx_systick_unmask_scheduler(); } else { /* Check if the task quantum for the running task has expired. */ if (time - sched_state.last_context_switch >= TASK_EXECUTION_QUANTUM) need_reschedule = TRUE; } /* Wake up tasks that have scheduled alarms. */ while (!mv_list_is_empty(sched_state.alarms_pending) && sched_state.alarms_pending->wakeup_time <= time) { struct mv_alarm_entry *a = sched_state.alarms_pending; mv_list_remove(sched_state.alarms_pending, sched_state.alarms_pending); mv__scheduler_task_unblock(a->task); nx_free(a); } /* Task switching time? */ if (need_reschedule) { if (sched_state.task_current != NULL) sched_state.task_current->stack_current = mv__task_get_stack(); reschedule(); mv__task_set_stack(sched_state.task_current->stack_current); sched_state.last_context_switch = nx_systick_get_ms(); } sched_lock = 0; }
void nxp_finalize(nxp_pool* pool) { nxp_chunk* c=pool->chunk; nxp_chunk* cp; int cnt=0; while (c!=pool->initial_chunk) { cp=c->prev; nx_free(c); cnt++; c=cp; } }
nxweb_result nxweb_cache_try(nxweb_http_server_connection* conn, nxweb_http_response* resp, const char* key, time_t if_modified_since, time_t revalidated_mtime) { if (*key==' ' || *key=='*') return NXWEB_MISS; // not implemented yet nxe_time_t loop_time=nxweb_get_loop_time(conn); ah_iter_t ci; //nxweb_log_error("trying cache for %s", fpath); pthread_mutex_lock(&_nxweb_cache_mutex); if ((ci=alignhash_get(nxweb_cache, _nxweb_cache, key))!=alignhash_end(_nxweb_cache)) { nxweb_cache_rec* rec=alignhash_value(_nxweb_cache, ci); if (rec->last_modified==revalidated_mtime) { rec->expires_time=loop_time+NXWEB_DEFAULT_CACHED_TIME; nxweb_log_info("revalidated %s in memcache", key); } if (loop_time <= rec->expires_time) { if (rec!=_nxweb_cache_head) { cache_rec_unlink(rec); cache_rec_link(rec); // relink to head } if (if_modified_since && rec->last_modified<=if_modified_since) { pthread_mutex_unlock(&_nxweb_cache_mutex); resp->status_code=304; resp->status="Not Modified"; return NXWEB_OK; } rec->ref_count++; // this must be within mutex-protected section pthread_mutex_unlock(&_nxweb_cache_mutex); resp->content_length=rec->content_length; resp->content=rec->content; resp->content_type=rec->content_type; resp->content_charset=rec->content_charset; resp->last_modified=rec->last_modified; resp->gzip_encoded=rec->gzip_encoded; conn->hsp.req_data=rec; conn->hsp.req_finalize=cache_rec_unref; return NXWEB_OK; } else if (!revalidated_mtime) { pthread_mutex_unlock(&_nxweb_cache_mutex); return NXWEB_REVALIDATE; } alignhash_del(nxweb_cache, _nxweb_cache, ci); cache_rec_unlink(rec); if (!rec->ref_count) { nx_free(rec); } else { // this is normal; just notification nxweb_log_error("removed %s [%p] from cache while its ref_count=%d", key, rec, rec->ref_count); } } pthread_mutex_unlock(&_nxweb_cache_mutex); return NXWEB_MISS; }
static void cache_finalize() { ah_iter_t ci; for (ci=alignhash_begin(_nxweb_cache); ci!=alignhash_end(_nxweb_cache); ci++) { if (alignhash_exist(_nxweb_cache, ci)) { nxweb_cache_rec* rec=alignhash_value(_nxweb_cache, ci); if (rec->ref_count) nxweb_log_error("file %s still in cache with ref_count=%d", alignhash_key(_nxweb_cache, ci), rec->ref_count); cache_rec_unlink(rec); nx_free(rec); } } alignhash_destroy(nxweb_cache, _nxweb_cache); pthread_mutex_destroy(&_nxweb_cache_mutex); }
void mv_semaphore_inc(mv_sem_t *sem) { mv_scheduler_lock(); sem->count++; /* If we are/were beyond what the semaphore can handle, we need to * wake up one of the blocked tasks. */ if (sem->count <= 0) { struct sem_task_handle *h = mv_list_pop_head(sem->blocked_tasks); mv__scheduler_task_unblock(h->task); nx_free(h); } mv_scheduler_unlock(); }
static inline void cache_check_size() { while (alignhash_size(_nxweb_cache)>NXWEB_MAX_CACHED_ITEMS) { nxweb_cache_rec* rec=_nxweb_cache_tail; while (rec && rec->ref_count) rec=rec->prev; if (rec) { const char* fpath=rec->content+rec->content_length+1; ah_iter_t ci=alignhash_get(nxweb_cache, _nxweb_cache, fpath); if (ci!=alignhash_end(_nxweb_cache)) { assert(rec==alignhash_value(_nxweb_cache, ci)); cache_rec_unlink(rec); alignhash_del(nxweb_cache, _nxweb_cache, ci); nx_free(rec); } } else { break; } } }
void nxp_gc(nxp_pool* pool) { if (!pool->chunk->prev) return; // can't free the very first chunk nxp_object *obj; int object_size=pool->object_size; int i; for (obj=pool->chunk->pool, i=pool->chunk->nitems; i>0; i--, obj=(nxp_object*)((char*)obj+object_size)) { if (obj->in_use) return; } // all objects in last chunk are not in use // => remove them from free list and free the chunk for (obj=pool->chunk->pool, i=pool->chunk->nitems; i>0; i--, obj=(nxp_object*)((char*)obj+object_size)) { if (obj->prev) obj->prev->next=obj->next; else pool->free_first=obj->next; if (obj->next) obj->next->prev=obj->prev; else pool->free_last=obj->prev; } nxp_chunk* c=pool->chunk; pool->chunk=pool->chunk->prev; nx_free(c); }
static void cache_rec_unref(nxd_http_server_proto* hsp, void* req_data) { pthread_mutex_lock(&_nxweb_cache_mutex); nxweb_cache_rec* rec=req_data; assert(rec->ref_count>0); if (!--rec->ref_count) { nxe_time_t loop_time=_nxweb_net_thread_data->loop->current_time; if (loop_time > rec->expires_time || !IS_LINKED(rec)) { const char* fpath=rec->content+rec->content_length+1; ah_iter_t ci=alignhash_get(nxweb_cache, _nxweb_cache, fpath); if (ci!=alignhash_end(_nxweb_cache) && rec==alignhash_value(_nxweb_cache, ci)) { alignhash_del(nxweb_cache, _nxweb_cache, ci); cache_rec_unlink(rec); } else { nxweb_log_error("freed previously removed cache entry %s [%p]", fpath, rec); } nx_free(rec); } } cache_check_size(); pthread_mutex_unlock(&_nxweb_cache_mutex); }
nxweb_result nxweb_cache_store_response(nxweb_http_server_connection* conn, nxweb_http_response* resp) { nxe_time_t loop_time=nxweb_get_loop_time(conn); if (!resp->status_code) resp->status_code=200; if (resp->status_code==200 && resp->sendfile_path // only cache content from files && resp->content_length>=0 && resp->content_length<=NXWEB_MAX_CACHED_ITEM_SIZE // must be small && resp->sendfile_offset==0 && resp->sendfile_end==resp->content_length // whole file only && resp->sendfile_end>=resp->sendfile_info.st_size // st_size could be zero if not initialized && alignhash_size(_nxweb_cache)<NXWEB_MAX_CACHED_ITEMS+16) { const char* fpath=resp->sendfile_path; const char* key=resp->cache_key; if (nxweb_cache_try(conn, resp, key, 0, resp->last_modified)!=NXWEB_MISS) return NXWEB_OK; nxweb_cache_rec* rec=nx_calloc(sizeof(nxweb_cache_rec)+resp->content_length+1+strlen(key)+1); rec->expires_time=loop_time+NXWEB_DEFAULT_CACHED_TIME; rec->last_modified=resp->last_modified; rec->content_type=resp->content_type; // assume content_type and content_charset come rec->content_charset=resp->content_charset; // from statically allocated memory, which won't go away rec->content_length=resp->content_length; rec->gzip_encoded=resp->gzip_encoded; char* ptr=((char*)rec)+offsetof(nxweb_cache_rec, content); int fd; if ((fd=open(fpath, O_RDONLY))<0 || read(fd, ptr, resp->content_length)!=resp->content_length) { if (fd>0) close(fd); nx_free(rec); nxweb_log_error("nxweb_cache_file_store_and_send(): [%s] stat() was OK, but open/read() failed", fpath); nxweb_send_http_error(resp, 500, "Internal Server Error"); return NXWEB_ERROR; } close(fd); resp->content=ptr; ptr+=resp->content_length; *ptr++='\0'; strcpy(ptr, key); key=ptr; int ret=0; ah_iter_t ci; pthread_mutex_lock(&_nxweb_cache_mutex); ci=alignhash_set(nxweb_cache, _nxweb_cache, key, &ret); if (ci!=alignhash_end(_nxweb_cache)) { if (ret!=AH_INS_ERR) { alignhash_value(_nxweb_cache, ci)=rec; cache_rec_link(rec); rec->ref_count++; cache_check_size(); pthread_mutex_unlock(&_nxweb_cache_mutex); nxweb_log_info("memcached %s", key); conn->hsp.req_data=rec; assert(!conn->hsp.req_finalize); conn->hsp.req_finalize=cache_rec_unref; //nxweb_start_sending_response(conn, resp); return NXWEB_OK; } else { // AH_INS_ERR => key already exists (added by other thread) nx_free(rec); rec=alignhash_value(_nxweb_cache, ci); resp->content_length=rec->content_length; resp->content=rec->content; resp->content_type=rec->content_type; resp->content_charset=rec->content_charset; resp->last_modified=rec->last_modified; resp->gzip_encoded=rec->gzip_encoded; rec->ref_count++; pthread_mutex_unlock(&_nxweb_cache_mutex); conn->hsp.req_data=rec; assert(!conn->hsp.req_finalize); conn->hsp.req_finalize=cache_rec_unref; //nxweb_start_sending_response(conn, resp); return NXWEB_OK; } } pthread_mutex_unlock(&_nxweb_cache_mutex); nx_free(rec); } return NXWEB_OK; }
void nxp_destroy(nxp_pool* pool) { nxp_finalize(pool); nx_free(pool); }
void _nx_delete_wcex(WNDCLASSEX *wcex) { UnregisterClass(wcex->lpszClassName,GetModuleHandle(0)); nx_free((void*)wcex->lpszClassName); }
/* Destroy the task that was just preempted. */ static inline void destroy_running_task(void) { mv_list_remove(sched_state.tasks_ready, sched_state.task_current); nx_free(sched_state.task_current->stack_base); nx_free(sched_state.task_current); sched_state.task_current = NULL; }
void mv_semaphore_destroy(mv_sem_t *sem) { mv_scheduler_lock(); NX_ASSERT(sem->count >= 0); nx_free(sem); mv_scheduler_unlock(); }