| 1110 | } |
| 1111 | |
| 1112 | static int |
| 1113 | vmem_xalloc_nextfit(vmem_t *vm, const vmem_size_t size, vmem_size_t align, |
| 1114 | const vmem_size_t phase, const vmem_size_t nocross, int flags, |
| 1115 | vmem_addr_t *addrp) |
| 1116 | { |
| 1117 | struct vmem_btag *bt, *cursor, *next, *prev; |
| 1118 | int error; |
| 1119 | |
| 1120 | error = ENOMEM; |
| 1121 | VMEM_LOCK(vm); |
| 1122 | |
| 1123 | /* |
| 1124 | * Make sure we have enough tags to complete the operation. |
| 1125 | */ |
| 1126 | if (bt_fill(vm, flags) != 0) |
| 1127 | goto out; |
| 1128 | |
| 1129 | retry: |
| 1130 | /* |
| 1131 | * Find the next free tag meeting our constraints. If one is found, |
| 1132 | * perform the allocation. |
| 1133 | */ |
| 1134 | for (cursor = &vm->vm_cursor, bt = TAILQ_NEXT(cursor, bt_seglist); |
| 1135 | bt != cursor; bt = TAILQ_NEXT(bt, bt_seglist)) { |
| 1136 | if (bt == NULL) |
| 1137 | bt = TAILQ_FIRST(&vm->vm_seglist); |
| 1138 | if (bt->bt_type == BT_TYPE_FREE && bt->bt_size >= size && |
| 1139 | (error = vmem_fit(bt, size, align, phase, nocross, |
| 1140 | VMEM_ADDR_MIN, VMEM_ADDR_MAX, addrp)) == 0) { |
| 1141 | vmem_clip(vm, bt, *addrp, size); |
| 1142 | break; |
| 1143 | } |
| 1144 | } |
| 1145 | |
| 1146 | /* |
| 1147 | * Try to coalesce free segments around the cursor. If we succeed, and |
| 1148 | * have not yet satisfied the allocation request, try again with the |
| 1149 | * newly coalesced segment. |
| 1150 | */ |
| 1151 | if ((next = TAILQ_NEXT(cursor, bt_seglist)) != NULL && |
| 1152 | (prev = TAILQ_PREV(cursor, vmem_seglist, bt_seglist)) != NULL && |
| 1153 | next->bt_type == BT_TYPE_FREE && prev->bt_type == BT_TYPE_FREE && |
| 1154 | prev->bt_start + prev->bt_size == next->bt_start) { |
| 1155 | prev->bt_size += next->bt_size; |
| 1156 | bt_remfree(vm, next); |
| 1157 | bt_remseg(vm, next); |
| 1158 | |
| 1159 | /* |
| 1160 | * The coalesced segment might be able to satisfy our request. |
| 1161 | * If not, we might need to release it from the arena. |
| 1162 | */ |
| 1163 | if (error == ENOMEM && prev->bt_size >= size && |
| 1164 | (error = vmem_fit(prev, size, align, phase, nocross, |
| 1165 | VMEM_ADDR_MIN, VMEM_ADDR_MAX, addrp)) == 0) { |
| 1166 | vmem_clip(vm, prev, *addrp, size); |
| 1167 | bt = prev; |
| 1168 | } else |
| 1169 | (void)vmem_try_release(vm, prev, true); |
no test coverage detected