/* Add an operation to the queue for tile @index * Note: if an operation affects more than one tile, it must be added once per tile. * * Concurrency: This function is not thread-safe on the same @self instance. */ void operation_queue_add(OperationQueue *self, TileIndex index, OperationDataDrawDab *op) { while (!tile_map_contains(self->tile_map, index)) { #ifdef HEAVY_DEBUG operation_queue_resize(self, self->tile_map->size+1); #else operation_queue_resize(self, self->tile_map->size*2); #endif } Fifo **queue_pointer = (Fifo **)tile_map_get(self->tile_map, index); Fifo *op_queue = *queue_pointer; if (op_queue == NULL) { // Lazy initialization op_queue = fifo_new(); *queue_pointer = op_queue; } if (fifo_peek_first(op_queue) == NULL) { // Critical section, not thread-safe if (!(self->dirty_tiles_n < self->tile_map->size*2*self->tile_map->size*2)) { // Prune duplicate tiles that cause us to almost exceed max self->dirty_tiles_n = remove_duplicate_tiles(self->dirty_tiles, self->dirty_tiles_n); } assert(self->dirty_tiles_n < self->tile_map->size*2*self->tile_map->size*2); self->dirty_tiles[self->dirty_tiles_n++] = index; } fifo_push(op_queue, (void *)op); }
/* Pop an operation off the queue for tile @index * The user of this function is reponsible for freeing the result using free() * * Concurrency: This function is reentrant (and lock-free) on different @index */ OperationDataDrawDab * operation_queue_pop(OperationQueue *self, TileIndex index) { OperationDataDrawDab *op = NULL; if (!tile_map_contains(self->tile_map, index)) { return NULL; } Fifo **queue_pointer = tile_map_get(self->tile_map, index); Fifo *op_queue = *queue_pointer; if (!op_queue) { return NULL; } op = fifo_pop(op_queue); if (!op) { // Queue empty fifo_free(op_queue, operation_delete_func); *queue_pointer = NULL; return NULL; } else { assert(op != NULL); return op; } }
OperationDataDrawDab * operation_queue_peek_last(OperationQueue *self, TileIndex index) { if (!tile_map_contains(self->tile_map, index)) { return NULL; } Fifo *op_queue = (Fifo *)*tile_map_get(self->tile_map, index); return (!op_queue) ? NULL : (OperationDataDrawDab *)fifo_peek_last(op_queue); }