void sp_writer_free_block (ShmBlock * block) { shm_alloc_space_block_dec (block->ablock); sp_shm_area_dec (block->pipe, block->area); spalloc_free (ShmBlock, block); }
static void sp_dec (ShmPipe * self) { self->use_count--; if (self->use_count > 0) return; while (self->shm_area) sp_shm_area_dec (self, self->shm_area); spalloc_free (ShmPipe, self); }
int sp_writer_resize (ShmPipe * self, size_t size) { ShmArea *newarea; ShmArea *old_current; ShmClient *client; int c = 0; int pathlen; if (self->shm_area->shm_area_len == size) return 0; newarea = sp_open_shm (NULL, ++self->next_area_id, 1, self->perms, size); if (!newarea) return -1; old_current = self->shm_area; newarea->next = self->shm_area; self->shm_area = newarea; pathlen = strlen (newarea->shm_area_name) + 1; for (client = self->clients; client; client = client->next) { struct CommandBuffer cb = { 0 }; if (!send_command (client->fd, &cb, COMMAND_CLOSE_SHM_AREA, old_current->id)) continue; cb.payload.new_shm_area.size = newarea->shm_area_len; cb.payload.new_shm_area.path_size = pathlen; if (!send_command (client->fd, &cb, COMMAND_NEW_SHM_AREA, newarea->id)) continue; if (send (client->fd, newarea->shm_area_name, pathlen, MSG_NOSIGNAL) != pathlen) continue; c++; } sp_shm_area_dec (self, old_current); return c; }
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; }
void sp_close (ShmPipe * self) { if (self->main_socket >= 0) close (self->main_socket); if (self->socket_path) { unlink (self->socket_path); free (self->socket_path); } while (self->clients) sp_writer_close_client (self, self->clients); while (self->shm_area) { sp_shm_area_dec (self, self->shm_area); } spalloc_free (ShmPipe, self); }
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_client_recv_finish (ShmPipe * self, char *buf) { ShmArea *shm_area = NULL; unsigned long offset; struct CommandBuffer cb = { 0 }; for (shm_area = self->shm_area; shm_area; shm_area = shm_area->next) { if (buf >= shm_area->shm_area && buf < shm_area->shm_area + shm_area->shm_area_len) break; } assert (shm_area); offset = buf - shm_area->shm_area; sp_shm_area_dec (self, shm_area); cb.payload.ack_buffer.offset = offset; return send_command (self->main_socket, &cb, COMMAND_ACK_BUFFER, self->shm_area->id); }
unsigned long sp_client_recv (ShmPipe * self, char **buf) { char *area_name = NULL; ShmArea *newarea, *oldarea; ShmArea *area; struct CommandBuffer cb; int retval; if (!recv_command (self->main_socket, &cb)) return -1; switch (cb.type) { case COMMAND_NEW_SHM_AREA: assert (cb.payload.new_shm_area.path_size > 0); assert (cb.payload.new_shm_area.size > 0); area_name = malloc (cb.payload.new_shm_area.path_size); retval = recv (self->main_socket, area_name, cb.payload.new_shm_area.path_size, 0); if (retval != cb.payload.new_shm_area.path_size) { free (area_name); return -3; } newarea = sp_open_shm (area_name, cb.area_id, 0, 0, cb.payload.new_shm_area.size); free (area_name); if (!newarea) return -4; oldarea = self->shm_area; newarea->next = self->shm_area; self->shm_area = newarea; /* if (oldarea) sp_shm_area_dec (self, oldarea); */ break; case COMMAND_CLOSE_SHM_AREA: for (area = self->shm_area; area; area = area->next) { if (area->id == cb.area_id) { sp_shm_area_dec (self, area); break; } } break; case COMMAND_NEW_BUFFER: assert (buf); for (area = self->shm_area; area; area = area->next) { if (area->id == cb.area_id) { *buf = area->shm_area + cb.payload.buffer.offset; sp_shm_area_inc (area); return cb.payload.buffer.size; } } return -23; default: return -99; } return 0; }