int a3d_workq_run(a3d_workq_t* self, void* task, int priority) { assert(self); assert(task); LOGD("debug task=%p, priority=%i", task, priority); pthread_mutex_lock(&self->mutex); // find the node containing the task or create a new one int status = A3D_WORKQ_ERROR; a3d_listitem_t* iter = NULL; a3d_listitem_t* pos = NULL; a3d_workqnode_t* tmp = NULL; a3d_workqnode_t* node = NULL; if((iter = a3d_list_find(self->queue_complete, task, a3d_taskcmp_fn)) != NULL) { // task completed node = (a3d_workqnode_t*) a3d_list_remove(self->queue_complete, &iter); status = node->status; a3d_workqnode_delete(&node); } else if((iter = a3d_list_find(self->queue_active, task, a3d_taskcmp_fn)) != NULL) { node = (a3d_workqnode_t*) a3d_list_peekitem(iter); node->purge_id = self->purge_id; status = A3D_WORKQ_PENDING; } else if((iter = a3d_list_find(self->queue_pending, task, a3d_taskcmp_fn)) != NULL) { node = (a3d_workqnode_t*) a3d_list_peekitem(iter); node->purge_id = self->purge_id; if(priority > node->priority) { // move up pos = a3d_list_prev(iter); while(pos) { tmp = (a3d_workqnode_t*) a3d_list_peekitem(pos); if(tmp->priority >= node->priority) { break; } pos = a3d_list_prev(pos); } if(pos) { // move after pos a3d_list_moven(self->queue_pending, iter, pos); } else { // move to head of list a3d_list_move(self->queue_pending, iter, NULL); } } else if(priority < node->priority) { // move down pos = a3d_list_next(iter); while(pos) { tmp = (a3d_workqnode_t*) a3d_list_peekitem(pos); if(tmp->priority < node->priority) { break; } pos = a3d_list_next(pos); } if(pos) { // move before pos a3d_list_move(self->queue_pending, iter, pos); } else { // move to tail of list a3d_list_moven(self->queue_pending, iter, NULL); } } node->priority = priority; status = A3D_WORKQ_PENDING; } else { // create new node node = a3d_workqnode_new(task, self->purge_id, priority); if(node == NULL) { goto fail_node; } else { // find the insert position pos = a3d_list_tail(self->queue_pending); while(pos) { tmp = (a3d_workqnode_t*) a3d_list_peekitem(pos); if(tmp->priority >= node->priority) { break; } pos = a3d_list_prev(pos); } if(pos) { // append after pos if(a3d_list_append(self->queue_pending, pos, (const void*) node) == NULL) { goto fail_queue; } } else { // insert at head of queue // first item or highest priority if(a3d_list_insert(self->queue_pending, NULL, (const void*) node) == NULL) { goto fail_queue; } } status = A3D_WORKQ_PENDING; // wake up workq thread pthread_cond_signal(&self->cond_pending); } } pthread_mutex_unlock(&self->mutex); // success return status; // failure fail_queue: a3d_workqnode_delete(&node); fail_node: pthread_mutex_unlock(&self->mutex); return A3D_WORKQ_ERROR; }
int a3d_multimap_add(a3d_multimap_t* self, const void* val, const char* key) { assert(self); assert(val); assert(key); a3d_listitem_t* item; // check if the list already exists a3d_hashmapIter_t iter; a3d_list_t* list; list = (a3d_list_t*) a3d_hashmap_find(self->hash, &iter, key); if(list && self->compare) { item = a3d_list_insertSorted(list, self->compare, val); if(item == NULL) { return 0; } return 1; } else if(list) { item = a3d_list_append(list, NULL, val); if(item == NULL) { return 0; } return 1; } // create a new list and add to hash list = a3d_list_new(); if(list == NULL) { return 0; } item = a3d_list_append(list, NULL, val); if(item == NULL) { goto fail_append; } if(a3d_hashmap_add(self->hash, (const void*) list, key) == 0) { goto fail_add; } // success return 1; // failure fail_add: a3d_list_remove(list, &item); fail_append: a3d_list_delete(&list); return 0; }