void kp_final_exit(ktap_state *ks) { if (!list_empty(&G(ks)->probe_events_head) || !list_empty(&G(ks)->timers)) kp_wait(ks); if (G(ks)->trace_task) put_task_struct(G(ks)->trace_task); kp_exit_timers(ks); kp_probe_exit(ks); /* free all resources got by ktap */ kp_tstring_freeall(ks); kp_free_all_gcobject(ks); cfunction_cache_exit(ks); wait_user_completion(ks); kp_transport_exit(ks); kp_exitthread(ks); kp_free(ks, ks->stack); free_all_ci(ks); free_kp_percpu_data(); free_cpumask_var(G(ks)->cpumask); kp_free(ks, ks); }
void vector_destroy(vector **v) { bool use_nvm; if (!v) { v_error("got NULL argument unexpectedly; returning\n"); return; } if (*v) { use_nvm = (*v)->use_nvm; (*v)->state = STATE_DEAD; kp_flush_range((void *)&((*v)->state), sizeof(ds_state), use_nvm); if ((*v)->data) { v_debug("testing 0: (*v)->data = %p\n", (*v)->data); kp_free((void **)&((*v)->data), use_nvm); //sets (*v)->data to NULL #ifdef VECTOR_ASSERT v_debug("testing 1: (*v)->data = %p\n", (*v)->data); if ((*v)->data != NULL) { v_die("kp_free() did not set (*v)->data to NULL as expected!\n"); } #endif } v_debug("testing 2: *v = %p\n", *v); kp_free((void **)(v), use_nvm); //sets *v to NULL after free #ifdef VECTOR_ASSERT v_debug("testing 3: *v = %p\n", *v); if (*v != NULL) { v_die("kp_free() did not set *v to NULL as expected!\n"); } #endif } v_debug("freed vector's array and vector struct itself\n"); }
void kp_obj_free_gclist(ktap_state *ks, ktap_gcobject *o) { while (o) { ktap_gcobject *next; next = gch(o)->next; switch (gch(o)->tt) { case KTAP_TYPE_TABLE: kp_tab_free(ks, (ktap_tab *)o); break; case KTAP_TYPE_PROTO: free_proto(ks, (ktap_proto *)o); break; case KTAP_TYPE_UPVAL: kp_freeupval(ks, (ktap_upval *)o); break; case KTAP_TYPE_PTABLE: kp_ptab_free(ks, (ktap_ptab *)o); break; case KTAP_TYPE_RAW: kp_free(ks, ((ktap_rawobj *)o)->v); break; default: kp_free(ks, o); } o = next; } }
void kp_table_free(ktap_State *ks, Table *t) { if (t->sizearray > 0) kp_free(ks, t->array); if (!isdummy(t->node)) kp_free(ks, t->node); kp_free(ks, t); }
int queue_create(queue **q, bool use_nvm) { #ifdef QUEUE_LOCK int ret; #endif if (!q) { tp_error("got a NULL argument: q=%p\n", q); return -1; } tp_debug("allocating a new queue\n"); kp_kpalloc((void **)q, sizeof(queue), use_nvm); if (!(*q)) { tp_error("malloc(queue) failed\n"); return -1; } (*q)->head = NULL; (*q)->tail = NULL; (*q)->len = 0; (*q)->use_nvm = use_nvm; #ifdef QUEUE_LOCK ret = kp_mutex_create("queue lock", &((*q)->lock)); if (ret != 0) { tp_error("mutex creation failed\n"); kp_free((void **)q, use_nvm); return -1; }; #endif tp_debug("allocated new queue, use_nvm = %s\n", use_nvm ? "true" : "false"); return 0; }
/* Function to free a task struct. In the hopefully uncommon event that this * function is called by queue_destroy() (i.e. the threadpool is destroyed * while there are still tasks left in the queue), then it is possible that * the task's arg will never be freed and cause a memory leak, because the * task_function was never called on the arg. Oh well. */ void task_free_fn(void *arg) { task *dead_task; if (arg) { dead_task = (task *)arg; kp_free((void **)(&dead_task), dead_task->use_nvm); } }
int main(int argc,char *argv[]) { KP *kp; KP_ARG *arg; KP_USER_INFO *user; kp=kp_init(argv[1],argv[2],argv[3],argv[4]); arg=kp_oauth_arg_init(kp); /* * 获取用户信息 * 如果成功则返回true * 出错则返回false并设置kp_errno * 如果可能的话kp->errmsg会有错误信息 */ if(kp_get_user_info(kp,arg,&user)) { printf("用户ID:%ld\n",user->user_id); printf("用户名:%s\n",user->user_name); printf("允许上传最大文件:%ld M\n",user->max_file_size/1024/1024); printf("用户空间总量:%ld M\n",user->quota_total/1024/1024); printf("用户已使用空间:%ld M\n",user->quota_used/1024/1024); printf("回收站空间使用量:%ld M\n",user->quota_recycled/1024/1024); //释放内存 kp_user_info_free(user); } else printf("%s",kp_error(kp->errmsg)); kp_free(kp); kp_arg_destroy(arg); return 0; }
void queue_destroy(queue *q) { element *head; element *next; if (!q) { tp_error("got a NULL argument: q=%p\n", q); return; } tp_debug("destroying the queue and its elements (if any)\n"); /* Free the queue's elements, if any: */ head = q->head; while (head) { #ifdef TP_ASSERT if (q->len == 0) { tp_die("unexpected: queue length hit 0 while destroying " "elements\n"); } if (q->len == 1) { if (head != q->tail) { tp_die("unexpected: head %p != q->tail %p\n", head, q->tail); } } #endif next = head->next; if (head->free_fn) { tp_debug("calling free_fn %p on data %p\n", head->free_fn, head->data); head->free_fn(head->data); } kp_free((void **)(&head), q->use_nvm); q->len -= 1; head = next; } /* Free the queue itself: */ #ifdef QUEUE_LOCK kp_mutex_destroy("queue lock", &(q->lock)); #endif kp_free((void **)(&q), q->use_nvm); tp_debug("destroyed the queue\n"); }
void threadpool_destroy(threadpool *tp, bool wait) { if (!tp) { tp_error("got a NULL argument: tp=%p\n", tp); return; } tp_debug("destroying thread pool; wait=%s, thread pool currently has " "%u workers\n", wait ? "true" : "false", tp->num_workers); /* In this initial implementation, we don't bother to keep track of * the worker thread IDs, so we can't force them to exit immediately * by using pthread_cancel() - this is a TODO item. * * Instead, we set worker_exit to true to tell all of the worker * threads to exit on their next loop, and then we wait for all of * them to exit themselves. When each thread exits, it MUST decrement * num_workers, and it must signal the exit_cond to wake up the thread * waiting here. ADDITIONALLY, the thread here must signal (broadcast, * really) the task_available condition on each loop, so that no worker * threads keep waiting for tasks to arrive. Make sure that the broadcast * happens BEFORE the wait! */ if (!wait) { tp_error("not supported yet: forced cancellation of worker threads. " "Will wait for them all to finish instead\n"); } tp->worker_exit = true; kp_mutex_lock("threadpool_destroy", tp->lock); while (tp->num_workers > 0) { ret = pthread_cond_broadcast(tp->task_available); if (ret != 0) { tp_error("pthread_cond_broadcast() returned error=%d; skipping " "thread cleanup!\n", ret); break; } ret = pthread_cond_wait(tp->exit_cond, tp->lock); if (ret != 0) { tp_error("pthread_cond_wait() returned error=%d; skipping " "thread cleanup!\n", ret); break; } } kp_mutex_unlock("threadpool_destroy", tp->lock); /* Now free everything that we allocated: */ kp_cond_destroy("exit cond", tp->exit); kp_cond_destroy("task_available cond", tp->task_available); kp_mutex_destroy("thread pool mutex", tp->lock); queue_destroy(tp->task_queue); kp_free((void **)(&tp), tp->use_nvm); tp_debug("successfully destroyed thread pool\n"); return 0; }
static void free_proto(ktap_state *ks, ktap_proto *f) { kp_free(ks, f->code); kp_free(ks, f->p); kp_free(ks, f->k); kp_free(ks, f->lineinfo); kp_free(ks, f->locvars); kp_free(ks, f->upvalues); kp_free(ks, f); }
static void free_ci(ktap_state *ks) { ktap_callinfo *ci = ks->ci; ktap_callinfo *next; if (!ci) return; next = ci->next; ci->next = NULL; while ((ci = next) != NULL) { next = ci->next; kp_free(ks, ci); } }
int queue_dequeue(queue *q, void **e) { element *head; if (!q || !e) { tp_error("got a NULL argument: q=%p, e=%p\n", q, e); return -1; } if (q->len == 0) { tp_debug("queue has no elements, returning 1\n"); return 1; } #ifdef TP_ASSERT if (!(q->head) || !(q->tail)) { tp_die("unexpected NULL pointer: q->head=%p, q->tail=%p\n", q->head, q->tail); } #endif /* Remember, the "head" of the queue is the "front" of the queue - the * element that we're dequeueing. Set the element pointer that will be * returned, then set the new head to be the current head's next element. * If we're dequeueing the last/only element in the queue, then both head * and tail are set to NULL. */ head = q->head; *e = head->data; if (head->next == NULL) { #ifdef TP_ASSERT if (q->len != 1) { tp_die("unexpected: queue length is %u, should be 1\n", q->len); } if (head != q->tail) { tp_die("unexpected: queue head %p and tail %p should be the " "same\n", head, q->tail); } #endif q->tail = NULL; } q->head = head->next; q->len -= 1; /* Don't forget to free the element that we allocated: */ kp_free((void **)(&head), q->use_nvm); tp_debug("returning element %p, queue length is now %u\n", *e, q->len); return 0; }
void kp_obj_free_gclist(ktap_state_t *ks, ktap_obj_t *o) { while (o) { ktap_obj_t *next; next = gch(o)->nextgc; switch (gch(o)->gct) { case ~KTAP_TTAB: kp_tab_free(ks, (ktap_tab_t *)o); break; case ~KTAP_TUPVAL: kp_freeupval(ks, (ktap_upval_t *)o); break; default: kp_free(ks, o); } o = next; } }
void threadpool_destroy(threadpool *tp, bool wait) { unsigned int uret; if (!tp) { tp_error("got a NULL argument: tp=%p\n", tp); return; } tp_debug("destroying thread pool; wait=%s, thread pool currently has " "%u workers\n", wait ? "true" : "false", tp->num_workers); /* In this initial implementation, we don't bother to keep track of * the worker thread IDs, so we can't force them to exit immediately * by using pthread_cancel() - this is a TODO item. * * We destroy the thread pool by simply looping on the worker remove * function until all of the threads have exited. */ if (!wait) { tp_error("not supported yet: forced cancellation of worker threads. " "Will wait for them all to finish instead\n"); } while (tp->num_workers > 0) { uret = threadpool_remove_worker(tp, wait); if (uret == UINT32_MAX || uret != tp->num_workers) { tp_error("threadpool_remove_worker() returned unexpected " "value %u; all threads may not be cleaned up!\n", uret); break; } } tp_debug("done waiting, destroying threadpool with task counts " "pending=%u, active=%u, completed=%u\n", tp->tasks_pending, tp->tasks_active, tp->tasks_completed); /* Now free everything that we allocated: */ kp_cond_destroy("exit cond", &(tp->exit_cond)); kp_cond_destroy("task_available cond", &(tp->task_available)); kp_mutex_destroy("thread pool mutex", &(tp->lock)); queue_destroy(tp->task_queue); kp_free((void **)(&tp), tp->use_nvm); tp_debug("successfully destroyed thread pool\n"); return; }
void kp_free_all_gcobject(ktap_State *ks) { Gcobject *o = G(ks)->allgc; Gcobject *next; while (o) { next = gch(o)->next; switch (gch(o)->tt) { case KTAP_TTABLE: kp_table_free(ks, (Table *)o); break; case KTAP_TPROTO: free_proto(ks, (Proto *)o); break; default: kp_free(ks, o); } o = next; } G(ks)->allgc = NULL; }
void kp_table_resize(ktap_State *ks, Table *t, int nasize, int nhsize) { int i; int oldasize = t->sizearray; int oldhsize = t->lsizenode; Node *nold = t->node; /* save old hash ... */ if (nasize > oldasize) /* array part must grow? */ setarrayvector(ks, t, nasize); /* create new hash part with appropriate size */ setnodevector(ks, t, nhsize); if (nasize < oldasize) { /* array part must shrink? */ t->sizearray = nasize; /* re-insert elements from vanishing slice */ for (i=nasize; i<oldasize; i++) { if (!ttisnil(&t->array[i])) kp_table_setint(ks, t, i + 1, &t->array[i]); } /* shrink array */ kp_realloc(ks, t->array, oldasize, nasize, Tvalue); } /* re-insert elements from hash part */ for (i = twoto(oldhsize) - 1; i >= 0; i--) { Node *old = nold+i; if (!ttisnil(gval(old))) { /* doesn't need barrier/invalidate cache, as entry was * already present in the table */ setobj(ks, kp_table_set(ks, t, gkey(old)), gval(old)); } } if (!isdummy(nold)) kp_free(ks, nold); /* free old array */ }
void vector_free_contents(vector *v) { unsigned long long i, count; if (v == NULL) { v_error("v is NULL\n"); return; } count = v->count; for (i = 0; i < count; i++) { if (v->data[i]) { v_debug("freeing element %s from slot %llu\n", (char *)(v->data[i]), i); kp_free(&(v->data[i]), v->use_nvm); //sets v->data[i] to NULL } else { /* could be a deleted value? */ v_debug("NULL pointer in array, not freeing it\n"); } } v_debug("successfully freed %llu elements from vector\n", count); }
/* * allocate raw object with size. * The raw object allocated will be free when ktap thread exit, * so user don't have to free it. */ void *kp_rawobj_alloc(ktap_state *ks, int size) { ktap_rawobj *obj; void *addr; addr = kp_zalloc(ks, size); if (unlikely(!addr)) { kp_error(ks, "alloc raw object size %d failed\n", size); return NULL; } obj = &kp_obj_newobject(ks, KTAP_TYPE_RAW, sizeof(ktap_rawobj), NULL)->rawobj; if (unlikely(!obj)) { kp_free(ks, addr); kp_error(ks, "alloc raw object failed\n"); return NULL; } obj->v = addr; /* return address of allocated memory, not raw object */ return addr; }
size_t track_flag_kp(const double kp_min, const double kp_max, satdata_mag *data, track_workspace *w) { size_t i; size_t nflagged = 0; /* number of points flagged */ size_t ntrack_flagged = 0; /* number of entire tracks flagged for UT */ kp_workspace *kp_p; int s; if (data->n == 0) return 0; kp_p = kp_alloc(KP_IDX_FILE); for (i = 0; i < w->n; ++i) { track_data *tptr = &(w->tracks[i]); time_t t = satdata_epoch2timet(tptr->t_eq); double kp; s = kp_get(t, &kp, kp_p); if (s == 0 && (kp < kp_min || kp > kp_max)) { nflagged += track_flag_track(i, TRACK_FLG_KP, data, w); ++ntrack_flagged; } } fprintf(stderr, "track_flag_kp: flagged %zu/%zu (%.1f%%) tracks due to kp\n", ntrack_flagged, w->n, (double) ntrack_flagged / (double) w->n * 100.0); kp_free(kp_p); return nflagged; } /* track_flag_kp() */
void kp_free_gclist(ktap_state *ks, ktap_gcobject *o) { while (o) { ktap_gcobject *next; next = gch(o)->next; switch (gch(o)->tt) { case KTAP_TTABLE: kp_table_free(ks, (ktap_table *)o); break; case KTAP_TPROTO: free_proto(ks, (ktap_proto *)o); break; #ifdef __KERNEL__ case KTAP_TPTABLE: kp_ptable_free(ks, (ktap_ptable *)o); break; #endif default: kp_free(ks, o); } o = next; } }
static void cfunction_cache_exit(ktap_state *ks) { kp_free(ks, G(ks)->cfunction_tbl); }
/* histogram: key should be number or string, value must be number */ void kp_table_histogram(ktap_State *ks, Table *t) { struct table_hist_record *thr; char dist_str[40]; int i, ratio, total = 0, count = 0; thr = kp_malloc(ks, sizeof(*thr) * (t->sizearray + sizenode(t))); for (i = 0; i < t->sizearray; i++) { Tvalue *v = &t->array[i]; if (isnil(v)) continue; if (!ttisnumber(v)) goto error; setnvalue(&thr[count++].key, i + 1); total += nvalue(v); } for (i = 0; i < sizenode(t); i++) { Node *n = &t->node[i]; int num; if (isnil(gkey(n))) continue; if (!ttisnumber(gval(n))) goto error; num = nvalue(gval(n)); setobj(ks, &thr[count].key, gkey(n)); setobj(ks, &thr[count].val, gval(n)); count++; total += nvalue(gval(n)); } sort(thr, count, sizeof(struct table_hist_record), hist_record_cmp, NULL); kp_printf(ks, "%32s%s%s\n", "value ", DISTRIBUTION_STR, " count"); dist_str[sizeof(dist_str) - 1] = '\0'; for (i = 0; i < count; i++) { Tvalue *key = &thr[i].key; Tvalue *val = &thr[i].val; memset(dist_str, ' ', sizeof(dist_str) - 1); ratio = (nvalue(val) * (sizeof(dist_str) - 1)) / total; memset(dist_str, '@', ratio); if (ttisstring(key)) { char buf[32 + 1] = {0}; char *keystr; if (strlen(svalue(key)) > 32) { strncpy(buf, svalue(key), 32-4); memset(buf + 32-4, '.', 3); keystr = buf; } else keystr = svalue(key); kp_printf(ks, "%32s |%s%-10d\n", keystr, dist_str, nvalue(val)); } else kp_printf(ks, "%32d | %s%-10d\n", nvalue(key), dist_str, nvalue(val)); } goto out; error: kp_printf(ks, "error: table histogram only handle " " (key: string/number val: number)\n"); out: kp_free(ks, thr); }
int threadpool_create(threadpool **tp, unsigned int num_workers, bool use_nvm) { int ret; unsigned int i, uret; if (!tp) { tp_error("got a NULL argument: tp=%p\n", tp); return -1; } if (num_workers == UINT32_MAX) { tp_error("invalid number of worker threads: %u\n", num_workers); return -1; } if (num_workers == 0) { tp_warn("creating a thread pool with 0 workers!\n"); } tp_debug("creating new thread pool with %u workers\n", num_workers); kp_kpalloc((void **)tp, sizeof(threadpool), use_nvm); if (!(*tp)) { tp_error("malloc(threadpool) failed\n"); return -1; } ret = queue_create(&((*tp)->task_queue), use_nvm); if (ret != 0) { tp_error("queue_create() returned error=%d\n", ret); goto free_pool; } ret = kp_mutex_create("thread pool mutex", &((*tp)->lock)); if (ret != 0) { tp_error("kp_mutex_create() returned error=%d\n", ret); goto free_queue; } ret = kp_cond_create("task_available cond", &((*tp)->task_available)); if (ret != 0) { tp_error("kp_cond_create(task_available) returned error=%d\n", ret); goto free_mutex; } ret = kp_cond_create("exit cond", &((*tp)->exit_cond)); if (ret != 0) { tp_error("kp_cond_create(exit_cond) returned error=%d\n", ret); goto free_cond1; } (*tp)->worker_exit = false; (*tp)->use_nvm = use_nvm; /* Now that allocation is done, add the workers. threadpool_add_worker() * will increment the num_workers count for us: */ (*tp)->num_workers = 0; for (i = 0; i < num_workers; i++) { uret = threadpool_add_worker(*tp); if (uret != i+1) { tp_error("threadpool_add_worker(%u) returned unexpected value " "%u\n", i, uret); for (; ; i--) { /* Don't wait, ignore return value: */ threadpool_remove_worker(*tp, false); if (i == 0) { break; } } goto free_cond2; } } (*tp)->tasks_pending = 0; (*tp)->tasks_active = 0; (*tp)->tasks_completed = 0; tp_debug("successfully created new thread pool with %u threads\n", (*tp)->num_workers); return 0; free_cond2: kp_cond_destroy("exit cond", &((*tp)->exit_cond)); free_cond1: kp_cond_destroy("task_available cond", &((*tp)->task_available)); free_mutex: kp_mutex_destroy("thread pool mutex", &((*tp)->lock)); free_queue: queue_destroy((*tp)->task_queue); free_pool: kp_free((void **)tp, use_nvm); return -1; }