static int list_ensure_space( list *a ) { int status = LIST_OK; if ( a->max==0 ) status = list_alloc( a ); else if ( a->n >= a->max ) status = list_realloc( a ); return status; }
int uproc_list_pop(uproc_list *list, void *value) { if (list->size < 1) { return uproc_error_msg(UPROC_EINVAL, "pop from empty list"); } uproc_list_get(list, list->size - 1, value); list->size--; if (list->size > list->capacity / 4) { return 0; } return list_realloc(list, list->capacity / 2); }
/* * obj_realloc_root -- (internal) reallocate root object */ static int obj_realloc_root(PMEMobjpool *pop, struct object_store *store, size_t size, size_t old_size, void (*constructor)(PMEMobjpool *pop, void *ptr, void *arg), void *arg) { LOG(3, "pop %p store %p size %zu old_size %zu", pop, store, size, old_size); struct list_head *lhead = &store->root.head; uint64_t size_offset = OOB_OFFSET_OF(lhead->pe_first, size); struct carg_realloc carg; carg.ptr = OBJ_OFF_TO_PTR(pop, lhead->pe_first.off); carg.old_size = old_size; carg.new_size = size; carg.user_type = POBJ_ROOT_TYPE_NUM; carg.constructor = constructor; carg.arg = arg; return list_realloc(pop, lhead, 0, NULL, size, constructor_zrealloc_root, &carg, size_offset, size, &lhead->pe_first); }
uproc_list *uproc_list_create(size_t value_size) { struct uproc_list_s *list; if (!value_size) { uproc_error_msg(UPROC_EINVAL, "value size must be non-zero"); return NULL; } list = malloc(sizeof *list); if (!list) { uproc_error(UPROC_ENOMEM); return NULL; } list->size = list->capacity = 0; list->value_size = value_size; list->data = NULL; if (list_realloc(list, 0)) { free(list); return NULL; } return list; }
/* Doubles the capacity of a list. If (value_size * capacity) would exceed * MAX_SIZE, use (MAX_SIZE / value_size) instead of doubling. * Fails if the size is already (MAX_SIZE / value_size). */ static int list_grow(struct uproc_list_s *list, long n) { long cap_req, cap_new, cap_max; cap_req = list->size + n; if (cap_req < list->capacity) { return 0; } cap_max = MAX_SIZE / list->value_size; if (list->capacity == cap_max || cap_req > cap_max) { return uproc_error_msg(UPROC_EINVAL, "list too big"); } if (cap_max / 2 > list->capacity) { cap_new = list->capacity * 2; } else { cap_new = cap_max; } if (cap_new < cap_req) { cap_new = cap_req; } return list_realloc(list, cap_new); }
/* * obj_realloc_common -- (internal) common routine for resizing * existing objects */ static int obj_realloc_common(PMEMobjpool *pop, struct object_store *store, PMEMoid *oidp, size_t size, unsigned int type_num, void (*constr_alloc)(PMEMobjpool *pop, void *ptr, void *arg), void (*constr_realloc)(PMEMobjpool *pop, void *ptr, void *arg)) { /* if OID is NULL just allocate memory */ if (OBJ_OID_IS_NULL(*oidp)) { struct carg_alloc carg; carg.size = size; /* if size is 0 - do nothing */ if (size == 0) return 0; return obj_alloc_construct(pop, oidp, size, type_num, constr_alloc, &carg); } if (size > PMEMOBJ_MAX_ALLOC_SIZE) { ERR("requested size too large"); errno = ENOMEM; return -1; } /* if size is 0 just free */ if (size == 0) { obj_free(pop, oidp); return 0; } struct carg_realloc carg; carg.ptr = OBJ_OFF_TO_PTR(pop, oidp->off); carg.new_size = size; carg.old_size = pmemobj_alloc_usable_size(*oidp); carg.user_type = type_num; carg.constructor = NULL; carg.arg = NULL; struct oob_header *pobj = OOB_HEADER_FROM_OID(pop, *oidp); uint16_t user_type_old = pobj->data.user_type; ASSERT(user_type_old < PMEMOBJ_NUM_OID_TYPES); if (type_num >= PMEMOBJ_NUM_OID_TYPES) { errno = EINVAL; ERR("!obj_realloc_construct"); LOG(2, "type_num has to be in range [0, %u]", PMEMOBJ_NUM_OID_TYPES - 1); return -1; } struct list_head *lhead_old = &store->bytype[user_type_old].head; if (type_num == user_type_old) { int ret = list_realloc(pop, lhead_old, 0, NULL, size, constr_realloc, &carg, 0, 0, oidp); if (ret) LOG(2, "list_realloc failed"); return ret; } else { struct list_head *lhead_new = &store->bytype[type_num].head; /* * Redo log updates 8 byte entries, so we have to prepare * full 8-byte value even if we want to update smaller field * (here: user_type). */ struct oob_header_data d = pobj->data; d.user_type = type_num; uint64_t data_offset = OOB_OFFSET_OF(*oidp, data); int ret = list_realloc_move(pop, lhead_old, lhead_new, 0, NULL, size, constr_realloc, &carg, data_offset, *((uint64_t *)&d), oidp); if (ret) LOG(2, "list_realloc_move failed"); return ret; } }
/* * obj_realloc_common -- (internal) common routine for resizing * existing objects */ static int obj_realloc_common(PMEMobjpool *pop, struct object_store *store, PMEMoid *oidp, size_t size, type_num_t type_num, int zero_init) { /* if OID is NULL just allocate memory */ if (OBJ_OID_IS_NULL(*oidp)) { /* if size is 0 - do nothing */ if (size == 0) return 0; return obj_alloc_construct(pop, oidp, size, type_num, zero_init, NULL, NULL); } if (size > PMEMOBJ_MAX_ALLOC_SIZE) { ERR("requested size too large"); errno = ENOMEM; return -1; } /* if size is 0 just free */ if (size == 0) { obj_free(pop, oidp); return 0; } struct carg_realloc carg; carg.ptr = OBJ_OFF_TO_PTR(pop, oidp->off); carg.new_size = size; carg.old_size = pmemobj_alloc_usable_size(*oidp); carg.user_type = type_num; carg.constructor = NULL; carg.arg = NULL; carg.zero_init = zero_init; struct oob_header *pobj = OOB_HEADER_FROM_OID(pop, *oidp); type_num_t user_type_old = pobj->data.user_type; /* callers should have checked this */ ASSERT(type_num < PMEMOBJ_NUM_OID_TYPES); ASSERT(user_type_old < PMEMOBJ_NUM_OID_TYPES); struct list_head *lhead_old = &store->bytype[user_type_old].head; if (type_num == user_type_old) { int ret = list_realloc(pop, lhead_old, 0, NULL, size, constructor_realloc, &carg, 0, 0, oidp); if (ret) LOG(2, "list_realloc failed"); /* oidp could be different, so we need to get the ptr again */ VALGRIND_DO_MAKE_MEM_NOACCESS(pop, &OOB_HEADER_FROM_OID(pop, *oidp)->data.padding, sizeof (OOB_HEADER_FROM_OID(pop, *oidp)->data.padding)); return ret; } else { struct list_head *lhead_new = &store->bytype[type_num].head; /* * Header padding doubles as a red zone to check for header * overwrites. Disable it temporarily so we can modify the type * number. */ VALGRIND_DO_MAKE_MEM_DEFINED(pop, &OOB_HEADER_FROM_OID(pop, *oidp)->data.padding, sizeof (OOB_HEADER_FROM_OID(pop, *oidp)->data.padding)); /* * Redo log updates 8 byte entries, so we have to prepare * full 8-byte value even if we want to update smaller field * (here: user_type). */ struct oob_header_data d = pobj->data; d.user_type = type_num; uint64_t data_offset = OOB_OFFSET_OF(*oidp, data); int ret = list_realloc_move(pop, lhead_old, lhead_new, 0, NULL, size, constructor_realloc, &carg, data_offset, *((uint64_t *)&d), oidp); if (ret) LOG(2, "list_realloc_move failed"); /* oidp could be different, so we need to get the ptr again */ VALGRIND_DO_MAKE_MEM_NOACCESS(pop, &OOB_HEADER_FROM_OID(pop, *oidp)->data.padding, sizeof (OOB_HEADER_FROM_OID(pop, *oidp)->data.padding)); return ret; } }