/** * Initializes a new player. * The player is placed in the queue of available players. */ struct player *player_init(struct player *p, struct game *g, double x, double y, double w, double h, uint32_t score, uint8_t data) { cpVect all[4] = {cpv(0,0), cpv(0,h), cpv(w,h), cpv(w,0)}; cpBody *body = cpBodyInit(&p->body, 10, cpMomentForBox(10, w, h)); if (!body) { ERR_ERRNO(); return 0; } cpBodySetPos(body, cpv(x,y)); //cpShape *shape = cpPolyShapeNew(body,4,all,cpv((p->l+p->r)/2.0,(p->b+p->t)/2.0)); cpShape *shape = cpPolyShapeInit(&p->shape, body, 4, all, cpv(0, 0)); if (!shape) { ERR_ERRNO(); cpBodyDestroy(body); return 0; } shape->data = p; shape->collision_type = PLAYER; if (linkedlist_add_last(g->p_q, p)) { ERR_TRACE(); cpBodyDestroy(body); cpShapeDestroy(shape); return 0; } p->x = x; p->y = y; p->node = g->p_q->last; return p; }
static void tea_thread_stop(int tid) { THREAD_WORK *tw; int r; /* wait until we have exclusive access right on ttable */ DBG("[tea] Thread %d killing scheduled.", tid); pthreadex_lock_get_exclusive_n(&ttable_lock, "kill-thread"); /* going to kill thread */ tw = ttable[tid]; pthreadex_lock_release(); if(tw != NULL) { DBG("[tea] Killing thread %d.", tid); /* consider it dead */ ttable[tid] = NULL; /* allow thread to do the cleanup */ DBG2("[tea] Approve cleanup..."); pthreadex_flag_up(&(tw->cleanup_do)); while((r = pthread_cancel(tw->pthread_id)) != 0 && errno == EINTR) { DBG("[tea] Cancel EINTR; repeating pthread_cancel() on %d", tid); errno = 0; } if(r != 0) ERR_ERRNO("[tea] Cannot cancel thread %d", tid); /* kill thread */ while((r = pthread_detach(tw->pthread_id)) != 0 && errno == EINTR) { DBG("[tea] Detach EINTR; repeating pthread_detach() on %d", tid); errno = 0; } if(r != 0) ERR_ERRNO("[tea] Cannot detach thread %d", tid); /* wait cleanup finishes */ DBG2("[tea] Wait cleanup termination..."); pthreadex_flag_wait(&(tw->cleanup_done)); DBG("[tea] THREAD %d KILLED!", tid); /* destroy flags && free mem */ pthreadex_flag_destroy(&(tw->mwaiting)); pthreadex_flag_destroy(&(tw->cleanup_do)); pthreadex_flag_destroy(&(tw->cleanup_done)); free(tw); } else ERR("[tea] Thread %d does not exist or died voluntarely.", tid); }
/** * Add the item at the specified location. */ int linkedlist_add(linkedlist *l, void *v, int loc) { if (loc == l->len) { return linkedlist_add_last(l,v); } else if (loc == 0) { return linkedlist_add_first(l,v); } else if (loc > l->len || loc < 0) { return 0; } linkedlist_node *n = malloc(sizeof(linkedlist_node)); if (!n) { ERR_ERRNO(); return -1; } n->data = v; int a; linkedlist_node *next = l->first; for (a = 0;a < loc;a++) next = next->next; n->prev = next->prev; n->next = next; next->prev->next = n; next->prev = n; l->len++; return 0; }
struct wall *wall_create(struct game *g, double l, double r, double b, double t) { struct wall *wa = calloc(1, sizeof(struct wall)); if (!wa) { ERR_ERRNO(); return 0; } return wall_init(wa, g, l, r, b, t); }
/** * Creates a new player by allocating memory and then initializing it. * \sa player_init */ struct player *player_create(struct game *g, double x, double y, double w, double h, uint32_t score, uint8_t data) { struct player *p = calloc(1, sizeof(struct player)); if (!p) { ERR_ERRNO(); return 0; } return player_init(p, g, x, y, w, h, score, data); }
/** * Create a bubble that will bounce around the screen. * \param g The game in which to create the bubble. * \param x The x location of the bubble. * \param y The y location of the bubble. * \param v_x The x velocity of the bubble. * \param v_y The y velocity of the bubble. * \param r The radius of the bubble. * \param l The bubble's life. */ struct bubble *bubble_create(double x, double y, double v_x, double v_y, double r, uint8_t l) { struct bubble *b = calloc(1, sizeof(struct bubble)); if (!b) { ERR_ERRNO(); return 0; } return bubble_init(b, x, y, v_x, v_y, r, l); }
/** * Create the linked list */ linkedlist *linkedlist_create() { linkedlist *cur = malloc(sizeof(linkedlist)); if (!cur) { ERR_ERRNO(); return 0; } cur->len = 0; cur->first = 0; cur->last = 0; return cur; }
/** * Create a duplicate list */ linkedlist *linkedlist_clone(linkedlist *l) { linkedlist *ll = malloc(sizeof(linkedlist)); if (!ll) { ERR_ERRNO(); return 0; } linkedlist_node *cur = l->first; for (;cur;cur = cur->next) { linkedlist_add_last(ll,cur->data); } return ll; }
/** * Initialize a bubble that will bounce around. * \param b The bubble to initialize. * \param x The x location of the bubble. * \param y The y location of the bubble. * \param v_x The x velocity of the bubble. * \param v_y The y velocity of the bubble. * \param r The radius of the bubble. * \param l The bubble's life. */ struct bubble *bubble_init(struct bubble *b, double x, double y, double v_x, double v_y, double r, uint8_t l) { cpBody *body = cpBodyInit(&b->body, r, cpMomentForCircle(r, 0, r, cpv(0, 0))); if (!body) { ERR_ERRNO(); return 0; } cpShape *shape = cpCircleShapeInit(&b->shape, body, r, cpv(0,0)); if (!shape) { cpBodyDestroy(body); ERR_ERRNO(); return 0; } cpBodySetVel(body, cpv(v_x, v_y)); cpBodySetPos(body, cpv(x, y)); shape->e = 1.0; shape->data = b; shape->collision_type = BUBBLE; b->l = l; return b; }
int linkedlist_add_last(linkedlist *l, void *v) { linkedlist_node *n = malloc(sizeof(linkedlist_node)); if (!n) { ERR_ERRNO(); return -1; } n->next = 0; n->data = v; n->prev = l->last; if (l->last) l->last->next = n; else l->first = n; l->last = n; l->len++; return 0; }
int tea_thread_msg_send(LN_CONTEXT *lnc, TEA_MSG *m, int delay) { static int pivot_id = 0; int tid = 0; if(delay > 0 || !lnc) { if(delay > 0) { /* calculate when */ if(clock_gettime(CLOCK_REALTIME, &m->w) < 0) { ERR_ERRNO("Cannot read CLOCK_REALTIME."); return -1; } DBG2("[tea] Now is %ld.%09ld", m->w.tv_sec, m->w.tv_nsec); m->w.tv_nsec += (delay % 1000) * 1000000;; m->w.tv_sec += (delay / 1000) * 1000000; if(m->w.tv_nsec > 1000000000) { m->w.tv_sec += m->w.tv_nsec / 1000000000; m->w.tv_nsec %= 1000000000; } } else { /* normal people send directly */ m->w.tv_nsec = 0; m->w.tv_sec = 0; } DBG("[tea] Packet queued and delayed until %ld.%09ld secs", m->w.tv_sec, m->w.tv_nsec); /* search sender and insert msg into its queue */ pthreadex_lock_get_shared(&ttable_lock); tid = pivot_id < 0 ? 0 : pivot_id; do { if(++tid >= cfg.maxthreads) tid = 0; if(ttable[tid] && ttable[tid]->to->sender) { /* insert into queue in correct order */ DBG2("[tea] Selected sender thread %d.", tid); mqueue_insert_delayed(ttable[tid]->mqueue, m); pthreadex_flag_up(&(ttable[tid]->mwaiting)); m = NULL; break; } } while(tid != pivot_id); pivot_id = tid; pthreadex_lock_release(); } /* if msg was not queued, then send it directly */ if(m) { if(lnc) { DBG("[tea] Packet is being sent now"); ln_send_packet(lnc, m->b, m->s, &m->dest); } else WRN("[tea] Cannot send message (lnc neither sender thread available)."); } return 0; }
static void tea_thread_new(int tid, TEA_OBJECT *to, SNODE *command) { THREAD_WORK *tw = NULL; TEA_OBJCFG *ocline; HASH_ITER hi; HASH_NODE *hn; int fatal = 0; DBG("[tea] Creating thread %d.", tid); if((tw = calloc(1, sizeof(THREAD_WORK))) == NULL) FAT("Cannot alloc THREAD_WORK struct for thread %d.", tid); tw->id = tid; tw->pthread_id = 0; tw->to = to; tw->options = hash_copy(command->command.thc.to->options); /* check methods */ if(tw->to->listener || tw->to->sender) tw->mqueue = mqueue_create(); pthreadex_flag_init(&(tw->mwaiting), 0); pthreadex_flag_name(&(tw->mwaiting), "mwaiting"); pthreadex_flag_init(&(tw->cleanup_do), 0); pthreadex_flag_name(&(tw->cleanup_do), "cleanup_do"); pthreadex_flag_init(&(tw->cleanup_done), 0); pthreadex_flag_name(&(tw->cleanup_done), "cleanup_done"); /* global thread initialization here */ if(tw->to->global_init && !tw->to->initialized) { tw->to->initialized = -1; tw->to->global_init(); } /* make space for thread data */ if((tw->data = calloc(1, to->datasize)) == NULL) FAT("%d:%s: No memory for thread data.", command->line, to->name); /* check config params */ if(to->cparams) { /* check only allowed params are defined */ for(hn = hash_iter_first(&hi, command->command.thc.to->options); !hash_iter_finished(&hi); hn = hash_iter_next(&hi)) { /* iterate all allowed params and stop if (1) declared */ /* parameter hn->key is found in allowed paramter list, */ /* or (2) stop if there is not moar allowed params */ for(ocline = to->cparams; ocline->name && strcasecmp(hn->key, ocline->name); ocline++) ; if(!ocline->name) FAT("%d:%s: Parameter %s not allowed here.", command->line, to->name, hn->key); } /* set params (apply configuration) */ for(ocline = to->cparams; ocline->name; ocline++) { SNODE *val; /* get configured value (or set default value if not specified) */ val = tea_thread_param_value_get(tw->options, ocline->name); /* check if parameter is optional */ if(!val && ocline->needed) FAT("%d:%s: Parameter %s is mandatory.", command->line, to->name, ocline->name); /* set value */ if(tea_thread_param_value_set(tw, ocline, val)) FAT("%d:%s: Cannot set parameter %s.", command->line, to->name, ocline->name); } } else { if(command->command.thc.to->options || command->command.thc.to->options->nentries > 0) FAT("%d:%s: Parameters not allowed for this type of thread.", command->line, to->name); } /* once configuration applied, launch thread configuration routine */ if(tw->to->configure && tw->to->configure(tw, command, 1)) FAT("%d:%s: Thread configuration failed.", command->line, to->name); /* add thread to the list */ pthreadex_lock_get_exclusive_n(&ttable_lock, "install-thread"); DBG("[tea] Installing thread %d.", tid); /* build threads */ if(ttable[tid]) FATAL_ERROR("Thread slot %d is used already.", tid); ttable[tid] = tw; /* launch thread */ if(pthread_create(&(tw->pthread_id), NULL, tea_thread, tw) != 0) { ERR_ERRNO("Error creating thread %d", tid); FATAL_ERROR("Fatal error happened during thread creation."); } termination: if(fatal && tw) { if(ttable[tid] == tw) ttable[tid] = NULL; if(tw->mqueue) mqueue_destroy(tw->mqueue); pthreadex_flag_destroy(&(tw->mwaiting)); pthreadex_flag_destroy(&(tw->cleanup_do)); pthreadex_flag_destroy(&(tw->cleanup_done)); free(tw); } pthreadex_lock_release(); if(!fatal) return; FAT("Aborting."); }