static int create_segments(unsigned long k_size, unsigned long v_size, yac_shared_segment_mmap **shared_segments_p, int *shared_segments_count, char **error_in) /* {{{ */ { yac_shared_segment *shared_segment; unsigned long allocate_size, occupied_size = 0;; unsigned int i, segment_size, segments_num = 1024; yac_shared_segment_mmap first_segment; k_size = YAC_SMM_ALIGNED_SIZE(k_size); v_size = YAC_SMM_ALIGNED_SIZE(v_size); while ((v_size / segments_num) < YAC_SMM_SEGMENT_MIN_SIZE) { segments_num >>= 1; } segment_size = v_size / segments_num; ++segments_num; allocate_size = k_size + v_size; first_segment.common.p = mmap(0, allocate_size, PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); if (first_segment.common.p == MAP_FAILED) { *error_in = "mmap"; return 0; } first_segment.size = allocate_size; first_segment.common.size = k_size; first_segment.common.pos = 0; *shared_segments_p = (yac_shared_segment_mmap *)calloc(1, segments_num * sizeof(yac_shared_segment_mmap)); if (!*shared_segments_p) { munmap(first_segment.common.p, first_segment.size); *error_in = "calloc"; return 0; } else { *shared_segments_p[0] = first_segment; } *shared_segments_count = segments_num; occupied_size = k_size; for (i = 1; i < segments_num; i++) { (*shared_segments_p)[i].size = 0; (*shared_segments_p)[i].common.pos = 0; (*shared_segments_p)[i].common.p = first_segment.common.p + occupied_size; if ((allocate_size - occupied_size) >= YAC_SMM_ALIGNED_SIZE(segment_size)) { (*shared_segments_p)[i].common.size = YAC_SMM_ALIGNED_SIZE(segment_size); occupied_size += YAC_SMM_ALIGNED_SIZE(segment_size); } else { (*shared_segments_p)[i].common.size = (allocate_size - occupied_size); break; } } return 1; }
int yac_allocator_startup(unsigned long k_size, unsigned long size, char **msg) /* {{{ */ { char *p; yac_shared_segment *segments = NULL; int i, segments_num, segments_array_size, segment_size; const yac_shared_memory_handlers *he; if ((he = &yac_shared_memory_handler)) { int ret = he->create_segments(k_size, size, &segments, &segments_num, msg); if (!ret) { if (segments) { int i; for (i = 0; i < segments_num; i++) { if (segments[i].p && segments[i].p != (void *)-1) { he->detach_segment(&segments[i]); } } free(segments); } return 0; } } else { return 0; } segment_size = he->segment_type_size(); segments_array_size = (segments_num - 1) * segment_size; yac_storage = segments[0].p; memcpy(&YAC_SG(first_seg), (char *)(&segments[0]), segment_size); YAC_SG(segments_num) = segments_num - 1; YAC_SG(segments_num_mask) = YAC_SG(segments_num) - 1; YAC_SG(segments) = (yac_shared_segment **)((char *)yac_storage + YAC_SMM_ALIGNED_SIZE(sizeof(yac_storage_globals) + segment_size - sizeof(yac_shared_segment))); p = (char *)YAC_SG(segments) + (sizeof(void *) * YAC_SG(segments_num)); memcpy(p, (char *)segments + segment_size, segments_array_size); for (i = 0; i < YAC_SG(segments_num); i++) { YAC_SG(segments)[i] = (yac_shared_segment *)p; p += segment_size; } YAC_SG(slots) = (yac_kv_key *)((char *)YAC_SG(segments) + (YAC_SG(segments_num) * sizeof(void *)) + YAC_SMM_ALIGNED_SIZE(segments_array_size)); free(segments); return 1; }
static int create_segments(size_t k_size, size_t v_size, yac_shared_segment_shm **shared_segments_p, int *shared_segments_count, char **error_in) /* {{{ */ { struct shmid_ds sds; int shm_id, shmget_flags; yac_shared_segment_shm *shared_segments, first_segment; unsigned int i, j, allocate_size, allocated_num, segments_num, segment_size; shmget_flags = IPC_CREAT|SHM_R|SHM_W|IPC_EXCL; segments_num = 1024; while ((v_size / segments_num) < YAC_SMM_SEGMENT_MIN_SIZE) { segments_num >>= 1; } segment_size = v_size / segments_num; allocate_size = YAC_SMM_SEGMENT_MAX_SIZE; while ((shm_id = shmget(IPC_PRIVATE, allocate_size, shmget_flags)) < 0) { allocate_size >>= 1; } if (shm_id < 0) { /* this should never happen */ *error_in = "shmget"; return 0; } if (allocate_size < YAC_SMM_SEGMENT_MIN_SIZE) { /* this should never happen */ *error_in = "shmget"; return 0; } if (k_size <= allocate_size) { first_segment.shm_id = shm_id; first_segment.common.pos = 0; first_segment.common.size = allocate_size; first_segment.common.p = shmat(shm_id, NULL, 0); shmctl(shm_id, IPC_RMID, &sds); if (first_segment.common.p == (void *)-1) { *error_in = "shmat"; return 0; } } else { shmctl(shm_id, IPC_RMID, &sds); *error_in = "shmget"; return 0; } allocated_num = (v_size % allocate_size)? (v_size / allocate_size) + 1 : (v_size / allocate_size); shared_segments = (yac_shared_segment_shm *)calloc(1, (allocated_num) * sizeof(yac_shared_segment_shm)); if (!shared_segments) { *error_in = "calloc"; return 0; } for (i = 0; i < allocated_num; i ++) { shm_id = shmget(IPC_PRIVATE, allocate_size, shmget_flags); if (shm_id == -1) { *error_in = "shmget"; for (j = 0; j < i; j++) { shmdt(shared_segments[j].common.p); } free(shared_segments); return 0; } shared_segments[i].shm_id = shm_id; shared_segments[i].common.pos = 0; shared_segments[i].common.size = allocate_size; shared_segments[i].common.p = shmat(shm_id, NULL, 0); shmctl(shm_id, IPC_RMID, &sds); if (shared_segments[i].common.p == (void *)-1) { *error_in = "shmat"; for (j = 0; j < i; j++) { shmdt(shared_segments[j].common.p); } free(shared_segments); return 0; } } ++segments_num; *shared_segments_p = (yac_shared_segment_shm *)calloc(1, segments_num * sizeof(yac_shared_segment_shm)); if (!*shared_segments_p) { free(shared_segments); *error_in = "calloc"; return 0; } else { *shared_segments_p[0] = first_segment; } *shared_segments_count = segments_num; j = 0; for (i = 1; i < segments_num; i++) { if (shared_segments[j].common.pos == 0) { (*shared_segments_p)[i].shm_id = shared_segments[j].shm_id; } if ((shared_segments[j].common.size - shared_segments[j].common.pos) >= (2 * YAC_SMM_ALIGNED_SIZE(segment_size))) { (*shared_segments_p)[i].common.pos = 0; (*shared_segments_p)[i].common.size = YAC_SMM_ALIGNED_SIZE(segment_size); (*shared_segments_p)[i].common.p = shared_segments[j].common.p + YAC_SMM_ALIGNED_SIZE(shared_segments[j].common.pos); shared_segments[j].common.pos += YAC_SMM_ALIGNED_SIZE(segment_size); } else { (*shared_segments_p)[i].common.pos = 0; (*shared_segments_p)[i].common.size = shared_segments[j].common.size - shared_segments[j].common.pos; (*shared_segments_p)[i].common.p = shared_segments[j].common.p + YAC_SMM_ALIGNED_SIZE(shared_segments[j].common.pos); j++; } } free(shared_segments); return 1; }