static int sp_shmbuf_dec (ShmPipe * self, ShmBuffer * buf, ShmBuffer * prev_buf) { buf->use_count--; if (buf->use_count == 0) { /* Remove from linked list */ if (prev_buf) prev_buf->next = buf->next; else self->buffers = buf->next; shm_alloc_space_block_dec (buf->block); sp_shm_area_dec (self, buf->shm_area); spalloc_free1 (sizeof (ShmBuffer) + sizeof (int) * buf->num_clients, buf); return 0; } return 1; }
static int sp_shmbuf_dec (ShmPipe * self, ShmBuffer * buf, ShmBuffer * prev_buf, ShmClient * client, void **tag) { int i; int had_client = 0; /** * Remove client from the list of buffer users. Here we make sure that * if a client closes connection but already decremented the use count * for this buffer, but other clients didn't have time to decrement * buffer will not be freed too early in sp_writer_close_client. */ for (i = 0; i < buf->num_clients; i++) { if (buf->clients[i] == client->fd) { buf->clients[i] = -1; had_client = 1; break; } } assert (had_client); buf->use_count--; if (buf->use_count == 0) { /* Remove from linked list */ if (prev_buf) prev_buf->next = buf->next; else self->buffers = buf->next; if (tag) *tag = buf->tag; shm_alloc_space_block_dec (buf->ablock); sp_shm_area_dec (self, buf->shm_area); spalloc_free1 (sizeof (ShmBuffer) + sizeof (int) * buf->num_clients, buf); return 0; } return 1; }
int sp_writer_send_buf (ShmPipe * self, char *buf, size_t size) { ShmArea *area = NULL; unsigned long offset = 0; unsigned long bsize = size; ShmBuffer *sb; ShmClient *client = NULL; ShmAllocBlock *block = NULL; int i = 0; int c = 0; if (self->num_clients == 0) return 0; for (area = self->shm_area; area; area = area->next) { if (buf >= area->shm_area && buf < (area->shm_area + area->shm_area_len)) { offset = buf - area->shm_area; block = shm_alloc_space_block_get (area->allocspace, offset); assert (block); break; } } if (!block) return -1; sb = spalloc_alloc (sizeof (ShmBuffer) + sizeof (int) * self->num_clients); memset (sb, 0, sizeof (ShmBuffer)); memset (sb->clients, -1, sizeof (int) * self->num_clients); sb->shm_area = area; sb->offset = offset; sb->size = size; sb->num_clients = self->num_clients; sb->block = block; for (client = self->clients; client; client = client->next) { struct CommandBuffer cb = { 0 }; cb.payload.buffer.offset = offset; cb.payload.buffer.size = bsize; if (!send_command (client->fd, &cb, COMMAND_NEW_BUFFER, self->shm_area->id)) continue; sb->clients[i++] = client->fd; c++; } if (c == 0) { spalloc_free1 (sizeof (ShmBuffer) + sizeof (int) * self->num_clients, sb); return 0; } sp_shm_area_inc (area); shm_alloc_space_block_inc (block); sb->use_count = c; sb->next = self->buffers; self->buffers = sb; return c; }