- Timestamp:
- 2011-05-21T16:23:17Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 0ff03f3
- Parents:
- 8d308b9 (diff), 13f2461 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - Location:
- uspace
- Files:
-
- 4 added
- 14 edited
-
app/klog/klog.c (modified) (4 diffs)
-
app/tester/Makefile (modified) (1 diff)
-
app/tester/mm/common.c (added)
-
app/tester/mm/common.h (added)
-
app/tester/mm/malloc1.c (modified) (13 diffs)
-
app/tester/mm/malloc3.c (added)
-
app/tester/mm/malloc3.def (added)
-
app/tester/tester.c (modified) (1 diff)
-
app/tester/tester.h (modified) (3 diffs)
-
lib/c/Makefile (modified) (1 diff)
-
lib/c/generic/assert.c (modified) (1 diff)
-
lib/c/generic/event.c (modified) (1 diff)
-
lib/c/generic/malloc.c (modified) (26 diffs)
-
lib/c/include/adt/list.h (modified) (6 diffs)
-
lib/c/include/as.h (modified) (1 diff)
-
lib/c/include/assert.h (modified) (3 diffs)
-
lib/c/include/event.h (modified) (1 diff)
-
lib/c/include/malloc.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/klog/klog.c
r8d308b9 r9d47440 44 44 #include <io/klog.h> 45 45 #include <sysinfo.h> 46 #include <malloc.h> 47 #include <fibril_synch.h> 48 #include <adt/list.h> 49 #include <adt/prodcons.h> 46 50 47 51 #define NAME "klog" 48 52 #define LOG_FNAME "/log/klog" 53 54 /* Producer/consumer buffers */ 55 typedef struct { 56 link_t link; 57 size_t length; 58 wchar_t *data; 59 } item_t; 60 61 static prodcons_t pc; 49 62 50 63 /* Pointer to klog area */ … … 52 65 static size_t klog_length; 53 66 54 static FILE *log; 55 56 static void interrupt_received(ipc_callid_t callid, ipc_call_t *call) 57 { 67 /* Notification mutex */ 68 static FIBRIL_MUTEX_INITIALIZE(mtx); 69 70 /** Klog producer 71 * 72 * Copies the contents of a character buffer to local 73 * producer/consumer queue. 74 * 75 * @param length Number of characters to copy. 76 * @param data Pointer to the kernel klog buffer. 77 * 78 */ 79 static void producer(size_t length, wchar_t *data) 80 { 81 item_t *item = (item_t *) malloc(sizeof(item_t)); 82 if (item == NULL) 83 return; 84 85 size_t sz = sizeof(wchar_t) * length; 86 wchar_t *buf = (wchar_t *) malloc(sz); 87 if (data == NULL) { 88 free(item); 89 return; 90 } 91 92 memcpy(buf, data, sz); 93 94 link_initialize(&item->link); 95 item->length = length; 96 item->data = buf; 97 prodcons_produce(&pc, &item->link); 98 } 99 100 /** Klog consumer 101 * 102 * Waits in an infinite loop for the character data created by 103 * the producer and outputs them to stdout and optionally into 104 * a file. 105 * 106 * @param data Unused. 107 * 108 * @return Always EOK (unreachable). 109 * 110 */ 111 static int consumer(void *data) 112 { 113 FILE *log = fopen(LOG_FNAME, "a"); 114 if (log == NULL) 115 printf("%s: Unable to create log file %s (%s)\n", NAME, LOG_FNAME, 116 str_error(errno)); 117 118 while (true) { 119 link_t *link = prodcons_consume(&pc); 120 item_t *item = list_get_instance(link, item_t, link); 121 122 for (size_t i = 0; i < item->length; i++) 123 putchar(item->data[i]); 124 125 if (log != NULL) { 126 for (size_t i = 0; i < item->length; i++) 127 fputc(item->data[i], log); 128 129 fflush(log); 130 fsync(fileno(log)); 131 } 132 133 free(item->data); 134 free(item); 135 } 136 137 fclose(log); 138 return EOK; 139 } 140 141 /** Kernel notification handler 142 * 143 * Receives kernel klog notifications. 144 * 145 * @param callid IPC call ID. 146 * @param call IPC call structure. 147 * 148 */ 149 static void notification_received(ipc_callid_t callid, ipc_call_t *call) 150 { 151 /* 152 * Make sure we process only a single notification 153 * at any time to limit the chance of the consumer 154 * starving. 155 * 156 * Note: Usually the automatic masking of the klog 157 * notifications on the kernel side does the trick 158 * of limiting the chance of accidentally copying 159 * the same data multiple times. However, due to 160 * the non-blocking architecture of klog notifications, 161 * this possibility cannot be generally avoided. 162 */ 163 164 fibril_mutex_lock(&mtx); 165 58 166 size_t klog_start = (size_t) IPC_GET_ARG1(*call); 59 167 size_t klog_len = (size_t) IPC_GET_ARG2(*call); 60 168 size_t klog_stored = (size_t) IPC_GET_ARG3(*call); 61 size_t i; 62 63 for (i = klog_len - klog_stored; i < klog_len; i++) { 64 wchar_t ch = klog[(klog_start + i) % klog_length]; 65 66 putchar(ch); 67 68 if (log != NULL) 69 fputc(ch, log); 70 } 71 72 if (log != NULL) { 73 fflush(log); 74 fsync(fileno(log)); 75 } 169 170 size_t offset = (klog_start + klog_len - klog_stored) % klog_length; 171 172 /* Copy data from the ring buffer */ 173 if (offset + klog_stored >= klog_length) { 174 size_t split = klog_length - offset; 175 176 producer(split, klog + offset); 177 producer(klog_stored - split, klog); 178 } else 179 producer(klog_stored, klog + offset); 180 181 event_unmask(EVENT_KLOG); 182 fibril_mutex_unlock(&mtx); 76 183 } 77 184 … … 111 218 } 112 219 220 prodcons_initialize(&pc); 221 async_set_interrupt_received(notification_received); 113 222 rc = event_subscribe(EVENT_KLOG, 0); 114 223 if (rc != EOK) { … … 118 227 } 119 228 120 log = fopen(LOG_FNAME, "a"); 121 if (log == NULL) 122 printf("%s: Unable to create log file %s (%s)\n", NAME, LOG_FNAME, 123 str_error(errno)); 124 125 async_set_interrupt_received(interrupt_received); 229 fid_t fid = fibril_create(consumer, NULL); 230 if (!fid) { 231 fprintf(stderr, "%s: Unable to create consumer fibril\n", 232 NAME); 233 return ENOMEM; 234 } 235 236 fibril_add_ready(fid); 237 event_unmask(EVENT_KLOG); 126 238 klog_update(); 239 240 task_retval(0); 127 241 async_manager(); 128 242 -
uspace/app/tester/Makefile
r8d308b9 r9d47440 48 48 ipc/ping_pong.c \ 49 49 loop/loop1.c \ 50 mm/common.c \ 50 51 mm/malloc1.c \ 51 52 mm/malloc2.c \ 53 mm/malloc3.c \ 52 54 devs/devman1.c \ 53 55 hw/misc/virtchar1.c \ -
uspace/app/tester/mm/malloc1.c
r8d308b9 r9d47440 30 30 31 31 #include <stdio.h> 32 #include <unistd.h>33 32 #include <stdlib.h> 34 #include <malloc.h>33 #include "common.h" 35 34 #include "../tester.h" 36 35 … … 45 44 */ 46 45 47 /**48 * sizeof_array49 * @array array to determine the size of50 *51 * Returns the size of @array in array elements.52 */53 #define sizeof_array(array) \54 (sizeof(array) / sizeof((array)[0]))55 56 #define MAX_ALLOC (16 * 1024 * 1024)57 58 /*59 * Subphase control structures: subphase termination conditions,60 * probabilities of individual actions, subphase control structure.61 */62 63 typedef struct {64 unsigned int max_cycles;65 unsigned int no_memory;66 unsigned int no_allocated;67 } sp_term_cond_s;68 69 typedef struct {70 unsigned int alloc;71 unsigned int free;72 } sp_action_prob_s;73 74 typedef struct {75 const char *name;76 sp_term_cond_s cond;77 sp_action_prob_s prob;78 } subphase_s;79 80 81 /*82 * Phase control structures: The minimum and maximum block size that83 * can be allocated during the phase execution, phase control structure.84 */85 86 typedef struct {87 size_t min_block_size;88 size_t max_block_size;89 } ph_alloc_size_s;90 91 typedef struct {92 const char *name;93 ph_alloc_size_s alloc;94 subphase_s *subphases;95 } phase_s;96 97 98 46 /* 99 47 * Subphases are defined separately here. This is for two reasons: … … 101 49 * how many subphases a phase contains. 102 50 */ 103 static subphase_ ssubphases_32B[] = {51 static subphase_t subphases_32B[] = { 104 52 { 105 53 .name = "Allocation", … … 140 88 }; 141 89 142 static subphase_ ssubphases_128K[] = {90 static subphase_t subphases_128K[] = { 143 91 { 144 92 .name = "Allocation", … … 179 127 }; 180 128 181 static subphase_ ssubphases_default[] = {129 static subphase_t subphases_default[] = { 182 130 { 183 131 .name = "Allocation", … … 217 165 } 218 166 }; 219 220 167 221 168 /* 222 169 * Phase definitions. 223 170 */ 224 static phase_ sphases[] = {171 static phase_t phases[] = { 225 172 { 226 173 .name = "32 B memory blocks", … … 257 204 }; 258 205 259 260 /* 261 * Global error flag. The flag is set if an error 262 * is encountered (overlapping blocks, inconsistent 263 * block data, etc.) 264 */ 265 static bool error_flag = false; 266 267 /* 268 * Memory accounting: the amount of allocated memory and the 269 * number and list of allocated blocks. 270 */ 271 static size_t mem_allocated; 272 static size_t mem_blocks_count; 273 274 static LIST_INITIALIZE(mem_blocks); 275 276 typedef struct { 277 /* Address of the start of the block */ 278 void *addr; 279 280 /* Size of the memory block */ 281 size_t size; 282 283 /* link to other blocks */ 284 link_t link; 285 } mem_block_s; 286 287 typedef mem_block_s *mem_block_t; 288 289 290 /** init_mem 291 * 292 * Initializes the memory accounting structures. 293 * 294 */ 295 static void init_mem(void) 206 static void do_subphase(phase_t *phase, subphase_t *subphase) 296 207 { 297 mem_allocated = 0; 298 mem_blocks_count = 0; 299 } 300 301 302 static bool overlap_match(link_t *entry, void *addr, size_t size) 303 { 304 mem_block_t mblk = list_get_instance(entry, mem_block_s, link); 305 306 /* Entry block control structure <mbeg, mend) */ 307 uint8_t *mbeg = (uint8_t *) mblk; 308 uint8_t *mend = (uint8_t *) mblk + sizeof(mem_block_s); 309 310 /* Entry block memory <bbeg, bend) */ 311 uint8_t *bbeg = (uint8_t *) mblk->addr; 312 uint8_t *bend = (uint8_t *) mblk->addr + mblk->size; 313 314 /* Data block <dbeg, dend) */ 315 uint8_t *dbeg = (uint8_t *) addr; 316 uint8_t *dend = (uint8_t *) addr + size; 317 318 /* Check for overlaps */ 319 if (((mbeg >= dbeg) && (mbeg < dend)) || 320 ((mend > dbeg) && (mend <= dend)) || 321 ((bbeg >= dbeg) && (bbeg < dend)) || 322 ((bend > dbeg) && (bend <= dend))) 323 return true; 324 325 return false; 326 } 327 328 329 /** test_overlap 330 * 331 * Test whether a block starting at @addr overlaps with another, previously 332 * allocated memory block or its control structure. 333 * 334 * @param addr Initial address of the block 335 * @param size Size of the block 336 * 337 * @return false if the block does not overlap. 338 * 339 */ 340 static int test_overlap(void *addr, size_t size) 341 { 342 link_t *entry; 343 bool fnd = false; 344 345 for (entry = mem_blocks.next; entry != &mem_blocks; entry = entry->next) { 346 if (overlap_match(entry, addr, size)) { 347 fnd = true; 348 break; 349 } 350 } 351 352 return fnd; 353 } 354 355 356 /** checked_malloc 357 * 358 * Allocate @size bytes of memory and check whether the chunk comes 359 * from the non-mapped memory region and whether the chunk overlaps 360 * with other, previously allocated, chunks. 361 * 362 * @param size Amount of memory to allocate 363 * 364 * @return NULL if the allocation failed. Sets the global error_flag to 365 * true if the allocation succeeded but is illegal. 366 * 367 */ 368 static void *checked_malloc(size_t size) 369 { 370 void *data; 371 372 /* Allocate the chunk of memory */ 373 data = malloc(size); 374 if (data == NULL) 375 return NULL; 376 377 /* Check for overlaps with other chunks */ 378 if (test_overlap(data, size)) { 379 TPRINTF("\nError: Allocated block overlaps with another " 380 "previously allocated block.\n"); 381 error_flag = true; 382 } 383 384 return data; 385 } 386 387 388 /** alloc_block 389 * 390 * Allocate a block of memory of @size bytes and add record about it into 391 * the mem_blocks list. Return a pointer to the block holder structure or 392 * NULL if the allocation failed. 393 * 394 * If the allocation is illegal (e.g. the memory does not come from the 395 * right region or some of the allocated blocks overlap with others), 396 * set the global error_flag. 397 * 398 * @param size Size of the memory block 399 * 400 */ 401 static mem_block_t alloc_block(size_t size) 402 { 403 /* Check for allocation limit */ 404 if (mem_allocated >= MAX_ALLOC) 405 return NULL; 406 407 /* Allocate the block holder */ 408 mem_block_t block = (mem_block_t) checked_malloc(sizeof(mem_block_s)); 409 if (block == NULL) 410 return NULL; 411 412 link_initialize(&block->link); 413 414 /* Allocate the block memory */ 415 block->addr = checked_malloc(size); 416 if (block->addr == NULL) { 417 free(block); 418 return NULL; 419 } 420 421 block->size = size; 422 423 /* Register the allocated block */ 424 list_append(&block->link, &mem_blocks); 425 mem_allocated += size + sizeof(mem_block_s); 426 mem_blocks_count++; 427 428 return block; 429 } 430 431 432 /** free_block 433 * 434 * Free the block of memory and the block control structure allocated by 435 * alloc_block. Set the global error_flag if an error occurs. 436 * 437 * @param block Block control structure 438 * 439 */ 440 static void free_block(mem_block_t block) 441 { 442 /* Unregister the block */ 443 list_remove(&block->link); 444 mem_allocated -= block->size + sizeof(mem_block_s); 445 mem_blocks_count--; 446 447 /* Free the memory */ 448 free(block->addr); 449 free(block); 450 } 451 452 453 /** expected_value 454 * 455 * Compute the expected value of a byte located at @pos in memory 456 * block described by @blk. 457 * 458 * @param blk Memory block control structure 459 * @param pos Position in the memory block data area 460 * 461 */ 462 static inline uint8_t expected_value(mem_block_t blk, uint8_t *pos) 463 { 464 return ((unsigned long) blk ^ (unsigned long) pos) & 0xff; 465 } 466 467 468 /** fill_block 469 * 470 * Fill the memory block controlled by @blk with data. 471 * 472 * @param blk Memory block control structure 473 * 474 */ 475 static void fill_block(mem_block_t blk) 476 { 477 uint8_t *pos; 478 uint8_t *end; 479 480 for (pos = blk->addr, end = pos + blk->size; pos < end; pos++) 481 *pos = expected_value(blk, pos); 482 } 483 484 485 /** check_block 486 * 487 * Check whether the block @blk contains the data it was filled with. 488 * Set global error_flag if an error occurs. 489 * 490 * @param blk Memory block control structure 491 * 492 */ 493 static void check_block(mem_block_t blk) 494 { 495 uint8_t *pos; 496 uint8_t *end; 497 498 for (pos = blk->addr, end = pos + blk->size; pos < end; pos++) { 499 if (*pos != expected_value (blk, pos)) { 500 TPRINTF("\nError: Corrupted content of a data block.\n"); 501 error_flag = true; 502 return; 503 } 504 } 505 } 506 507 508 static link_t *list_get_nth(link_t *list, unsigned int i) 509 { 510 unsigned int cnt = 0; 511 link_t *entry; 512 513 for (entry = list->next; entry != list; entry = entry->next) { 514 if (cnt == i) 515 return entry; 516 517 cnt++; 518 } 519 520 return NULL; 521 } 522 523 524 /** get_random_block 525 * 526 * Select a random memory block from the list of allocated blocks. 527 * 528 * @return Block control structure or NULL if the list is empty. 529 * 530 */ 531 static mem_block_t get_random_block(void) 532 { 533 if (mem_blocks_count == 0) 534 return NULL; 535 536 unsigned int blkidx = rand() % mem_blocks_count; 537 link_t *entry = list_get_nth(&mem_blocks, blkidx); 538 539 if (entry == NULL) { 540 TPRINTF("\nError: Corrupted list of allocated memory blocks.\n"); 541 error_flag = true; 542 } 543 544 return list_get_instance(entry, mem_block_s, link); 545 } 546 547 548 #define RETURN_IF_ERROR \ 549 { \ 550 if (error_flag) \ 551 return; \ 552 } 553 554 555 static void do_subphase(phase_s *phase, subphase_s *subphase) 556 { 557 unsigned int cycles; 558 for (cycles = 0; /* always */; cycles++) { 559 560 if (subphase->cond.max_cycles && 561 cycles >= subphase->cond.max_cycles) { 208 for (unsigned int cycles = 0; /* always */; cycles++) { 209 210 if ((subphase->cond.max_cycles) && 211 (cycles >= subphase->cond.max_cycles)) { 562 212 /* 563 213 * We have performed the required number of … … 572 222 unsigned int rnd = rand() % 100; 573 223 if (rnd < subphase->prob.alloc) { 574 /* Compute a random number lying in interval <min_block_size, max_block_size> */ 224 /* 225 * Compute a random number lying in interval 226 * <min_block_size, max_block_size> 227 */ 575 228 int alloc = phase->alloc.min_block_size + 576 229 (rand() % (phase->alloc.max_block_size - phase->alloc.min_block_size + 1)); 577 230 578 mem_block_t blk = alloc_block(alloc);231 mem_block_t *blk = alloc_block(alloc); 579 232 RETURN_IF_ERROR; 580 233 … … 585 238 break; 586 239 } 587 588 240 } else { 589 241 TPRINTF("A"); 590 242 fill_block(blk); 243 RETURN_IF_ERROR; 591 244 } 592 245 593 246 } else if (rnd < subphase->prob.free) { 594 mem_block_t blk = get_random_block();247 mem_block_t *blk = get_random_block(); 595 248 if (blk == NULL) { 596 249 TPRINTF("F(R)"); … … 599 252 break; 600 253 } 601 602 254 } else { 603 255 TPRINTF("R"); … … 614 266 } 615 267 616 617 static void do_phase(phase_s *phase) 268 static void do_phase(phase_t *phase) 618 269 { 619 unsigned int subno; 620 621 for (subno = 0; subno < 3; subno++) { 622 subphase_s *subphase = & phase->subphases [subno]; 270 for (unsigned int subno = 0; subno < 3; subno++) { 271 subphase_t *subphase = &phase->subphases[subno]; 623 272 624 273 TPRINTF(".. Sub-phase %u (%s)\n", subno + 1, subphase->name); … … 632 281 init_mem(); 633 282 634 unsigned int phaseno;635 for (phaseno = 0; phaseno < sizeof_array(phases);phaseno++) {636 phase_ s*phase = &phases[phaseno];283 for (unsigned int phaseno = 0; phaseno < sizeof_array(phases); 284 phaseno++) { 285 phase_t *phase = &phases[phaseno]; 637 286 638 287 TPRINTF("Entering phase %u (%s)\n", phaseno + 1, phase->name); … … 645 294 } 646 295 296 TPRINTF("Cleaning up.\n"); 297 done_mem(); 647 298 if (error_flag) 648 299 return "Test failed"; -
uspace/app/tester/tester.c
r8d308b9 r9d47440 63 63 #include "mm/malloc1.def" 64 64 #include "mm/malloc2.def" 65 #include "mm/malloc3.def" 65 66 #include "hw/serial/serial1.def" 66 67 #include "hw/misc/virtchar1.def" -
uspace/app/tester/tester.h
r8d308b9 r9d47440 38 38 #include <sys/types.h> 39 39 #include <bool.h> 40 #include <stacktrace.h> 40 41 41 42 #define IPC_TEST_SERVICE 10240 … … 46 47 extern char **test_argv; 47 48 49 /** 50 * sizeof_array 51 * @array array to determine the size of 52 * 53 * Returns the size of @array in array elements. 54 */ 55 #define sizeof_array(array) \ 56 (sizeof(array) / sizeof((array)[0])) 57 48 58 #define TPRINTF(format, ...) \ 49 { \59 do { \ 50 60 if (!test_quiet) { \ 51 fprintf(stderr, format, ##__VA_ARGS__); \61 fprintf(stderr, (format), ##__VA_ARGS__); \ 52 62 } \ 53 } 63 } while (0) 64 65 #define TSTACKTRACE() \ 66 do { \ 67 if (!test_quiet) { \ 68 stacktrace_print(); \ 69 } \ 70 } while (0) 54 71 55 72 typedef const char *(*test_entry_t)(void); … … 79 96 extern const char *test_malloc1(void); 80 97 extern const char *test_malloc2(void); 98 extern const char *test_malloc3(void); 81 99 extern const char *test_serial1(void); 82 100 extern const char *test_virtchar1(void); -
uspace/lib/c/Makefile
r8d308b9 r9d47440 108 108 generic/adt/measured_strings.c \ 109 109 generic/adt/char_map.c \ 110 generic/adt/prodcons.c \ 110 111 generic/time.c \ 111 112 generic/stdlib.c \ -
uspace/lib/c/generic/assert.c
r8d308b9 r9d47440 33 33 #include <assert.h> 34 34 #include <stdio.h> 35 #include <io/klog.h> 35 36 #include <stdlib.h> 37 #include <atomic.h> 36 38 #include <stacktrace.h> 37 39 38 void assert_abort(const char *cond, const char *file, unsigned int line) 40 #define MSG_START "Assertion failed (" 41 #define MSG_FILE ") in file \"" 42 #define MSG_LINE "\", line " 43 #define MSG_END ".\n" 44 45 static atomic_t failed_asserts; 46 47 void assert_abort(const char *cond, const char *file, const char *line) 39 48 { 40 printf("Assertion failed (%s) in file \"%s\", line %u.\n", 49 /* 50 * Send the message safely to klog. Nested asserts should not occur. 51 */ 52 klog_write(MSG_START, str_size(MSG_START)); 53 klog_write(cond, str_size(cond)); 54 klog_write(MSG_FILE, str_size(MSG_FILE)); 55 klog_write(file, str_size(file)); 56 klog_write(MSG_LINE, str_size(MSG_LINE)); 57 klog_write(line, str_size(line)); 58 klog_write(MSG_END, str_size(MSG_END)); 59 60 /* 61 * Check if this is a nested or parallel assert. 62 */ 63 if (atomic_postinc(&failed_asserts)) 64 abort(); 65 66 /* 67 * Attempt to print the message to standard output and display 68 * the stack trace. These operations can theoretically trigger nested 69 * assertions. 70 */ 71 printf(MSG_START "%s" MSG_FILE "%s" MSG_LINE "%s" MSG_END, 41 72 cond, file, line); 42 73 stacktrace_print(); 74 43 75 abort(); 44 76 } -
uspace/lib/c/generic/event.c
r8d308b9 r9d47440 41 41 #include <kernel/ipc/event_types.h> 42 42 43 /** Subscribe forevent notifications.43 /** Subscribe event notifications. 44 44 * 45 * @param evno Event number.46 * @param method Use thismethod for notifying me.45 * @param evno Event type to subscribe. 46 * @param imethod Use this interface and method for notifying me. 47 47 * 48 48 * @return Value returned by the kernel. 49 * 49 50 */ 50 int event_subscribe(event_type_t e , sysarg_tmethod)51 int event_subscribe(event_type_t evno, sysarg_t imethod) 51 52 { 52 return __SYSCALL2(SYS_EVENT_SUBSCRIBE, (sysarg_t) e, (sysarg_t) method); 53 return __SYSCALL2(SYS_EVENT_SUBSCRIBE, (sysarg_t) evno, 54 (sysarg_t) imethod); 55 } 56 57 /** Unmask event notifications. 58 * 59 * @param evno Event type to unmask. 60 * 61 * @return Value returned by the kernel. 62 * 63 */ 64 int event_unmask(event_type_t evno) 65 { 66 return __SYSCALL1(SYS_EVENT_UNMASK, (sysarg_t) evno); 53 67 } 54 68 -
uspace/lib/c/generic/malloc.c
r8d308b9 r9d47440 65 65 #define BASE_ALIGN 16 66 66 67 /** Heap shrink granularity 68 * 69 * Try not to pump and stress the heap to much 70 * by shrinking and enlarging it too often. 71 * A heap area won't shrunk if it the released 72 * free block is smaller than this constant. 73 * 74 */ 75 #define SHRINK_GRANULARITY (64 * PAGE_SIZE) 76 67 77 /** Overhead of each heap block. */ 68 78 #define STRUCT_OVERHEAD \ … … 86 96 * 87 97 */ 88 #define AREA_FIRST_BLOCK (area) \98 #define AREA_FIRST_BLOCK_HEAD(area) \ 89 99 (ALIGN_UP(((uintptr_t) (area)) + sizeof(heap_area_t), BASE_ALIGN)) 100 101 /** Get last block in heap area. 102 * 103 */ 104 #define AREA_LAST_BLOCK_FOOT(area) \ 105 (((uintptr_t) (area)->end) - sizeof(heap_block_foot_t)) 106 107 /** Get header in heap block. 108 * 109 */ 110 #define BLOCK_HEAD(foot) \ 111 ((heap_block_head_t *) \ 112 (((uintptr_t) (foot)) + sizeof(heap_block_foot_t) - (foot)->size)) 90 113 91 114 /** Get footer in heap block. … … 94 117 #define BLOCK_FOOT(head) \ 95 118 ((heap_block_foot_t *) \ 96 (((uintptr_t) head) + head->size - sizeof(heap_block_foot_t)))119 (((uintptr_t) (head)) + (head)->size - sizeof(heap_block_foot_t))) 97 120 98 121 /** Heap area. … … 115 138 void *end; 116 139 140 /** Previous heap area */ 141 struct heap_area *prev; 142 117 143 /** Next heap area */ 118 144 struct heap_area *next; … … 161 187 /** Futex for thread-safe heap manipulation */ 162 188 static futex_t malloc_futex = FUTEX_INITIALIZER; 189 190 #ifndef NDEBUG 191 192 #define malloc_assert(expr) \ 193 do { \ 194 if (!(expr)) {\ 195 futex_up(&malloc_futex); \ 196 assert_abort(#expr, __FILE__, STR2(__LINE__)); \ 197 } \ 198 } while (0) 199 200 #else /* NDEBUG */ 201 202 #define malloc_assert(expr) 203 204 #endif /* NDEBUG */ 163 205 164 206 /** Initialize a heap block … … 202 244 heap_block_head_t *head = (heap_block_head_t *) addr; 203 245 204 assert(head->magic == HEAP_BLOCK_HEAD_MAGIC);246 malloc_assert(head->magic == HEAP_BLOCK_HEAD_MAGIC); 205 247 206 248 heap_block_foot_t *foot = BLOCK_FOOT(head); 207 249 208 assert(foot->magic == HEAP_BLOCK_FOOT_MAGIC);209 assert(head->size == foot->size);250 malloc_assert(foot->magic == HEAP_BLOCK_FOOT_MAGIC); 251 malloc_assert(head->size == foot->size); 210 252 } 211 253 212 254 /** Check a heap area structure 213 255 * 256 * Should be called only inside the critical section. 257 * 214 258 * @param addr Address of the heap area. 215 259 * … … 219 263 heap_area_t *area = (heap_area_t *) addr; 220 264 221 assert(area->magic == HEAP_AREA_MAGIC); 222 assert(area->start < area->end); 223 assert(((uintptr_t) area->start % PAGE_SIZE) == 0); 224 assert(((uintptr_t) area->end % PAGE_SIZE) == 0); 265 malloc_assert(area->magic == HEAP_AREA_MAGIC); 266 malloc_assert(addr == area->start); 267 malloc_assert(area->start < area->end); 268 malloc_assert(((uintptr_t) area->start % PAGE_SIZE) == 0); 269 malloc_assert(((uintptr_t) area->end % PAGE_SIZE) == 0); 225 270 } 226 271 227 272 /** Create new heap area 228 273 * 229 * @param start Preffered starting address of the new area. 230 * @param size Size of the area. 274 * Should be called only inside the critical section. 275 * 276 * @param size Size of the area. 231 277 * 232 278 */ … … 248 294 249 295 area->start = astart; 250 area->end = (void *) 251 ALIGN_DOWN((uintptr_t) astart + asize, BASE_ALIGN);296 area->end = (void *) ((uintptr_t) astart + asize); 297 area->prev = NULL; 252 298 area->next = NULL; 253 299 area->magic = HEAP_AREA_MAGIC; 254 300 255 void *block = (void *) AREA_FIRST_BLOCK (area);301 void *block = (void *) AREA_FIRST_BLOCK_HEAD(area); 256 302 size_t bsize = (size_t) (area->end - block); 257 303 … … 262 308 last_heap_area = area; 263 309 } else { 310 area->prev = last_heap_area; 264 311 last_heap_area->next = area; 265 312 last_heap_area = area; … … 271 318 /** Try to enlarge a heap area 272 319 * 320 * Should be called only inside the critical section. 321 * 273 322 * @param area Heap area to grow. 274 * @param size Gross size of item to allocate (bytes). 323 * @param size Gross size to grow (bytes). 324 * 325 * @return True if successful. 275 326 * 276 327 */ … … 282 333 area_check(area); 283 334 284 size_t asize = ALIGN_UP((size_t) (area->end - area->start) + size,285 PAGE_SIZE);286 287 335 /* New heap area size */ 288 void *end = (void *) 289 ALIGN_DOWN((uintptr_t) area->start + asize, BASE_ALIGN); 336 size_t gross_size = (size_t) (area->end - area->start) + size; 337 size_t asize = ALIGN_UP(gross_size, PAGE_SIZE); 338 void *end = (void *) ((uintptr_t) area->start + asize); 290 339 291 340 /* Check for overflow */ … … 299 348 300 349 /* Add new free block */ 301 block_init(area->end, (size_t) (end - area->end), true, area); 350 size_t net_size = (size_t) (end - area->end); 351 if (net_size > 0) 352 block_init(area->end, net_size, true, area); 302 353 303 354 /* Update heap area parameters */ … … 309 360 /** Try to enlarge any of the heap areas 310 361 * 362 * Should be called only inside the critical section. 363 * 311 364 * @param size Gross size of item to allocate (bytes). 312 365 * … … 318 371 319 372 /* First try to enlarge some existing area */ 320 heap_area_t *area;321 for (area = first_heap_area; area != NULL;area = area->next) {373 for (heap_area_t *area = first_heap_area; area != NULL; 374 area = area->next) { 322 375 if (area_grow(area, size)) 323 376 return true; … … 325 378 326 379 /* Eventually try to create a new area */ 327 return area_create(AREA_FIRST_BLOCK(size)); 328 } 329 330 /** Try to shrink heap space 331 * 380 return area_create(AREA_FIRST_BLOCK_HEAD(size)); 381 } 382 383 /** Try to shrink heap 384 * 385 * Should be called only inside the critical section. 332 386 * In all cases the next pointer is reset. 333 387 * 334 */ 335 static void heap_shrink(void) 336 { 388 * @param area Last modified heap area. 389 * 390 */ 391 static void heap_shrink(heap_area_t *area) 392 { 393 area_check(area); 394 395 heap_block_foot_t *last_foot = 396 (heap_block_foot_t *) AREA_LAST_BLOCK_FOOT(area); 397 heap_block_head_t *last_head = BLOCK_HEAD(last_foot); 398 399 block_check((void *) last_head); 400 malloc_assert(last_head->area == area); 401 402 if (last_head->free) { 403 /* 404 * The last block of the heap area is 405 * unused. The area might be potentially 406 * shrunk. 407 */ 408 409 heap_block_head_t *first_head = 410 (heap_block_head_t *) AREA_FIRST_BLOCK_HEAD(area); 411 412 block_check((void *) first_head); 413 malloc_assert(first_head->area == area); 414 415 size_t shrink_size = ALIGN_DOWN(last_head->size, PAGE_SIZE); 416 417 if (first_head == last_head) { 418 /* 419 * The entire heap area consists of a single 420 * free heap block. This means we can get rid 421 * of it entirely. 422 */ 423 424 heap_area_t *prev = area->prev; 425 heap_area_t *next = area->next; 426 427 if (prev != NULL) { 428 area_check(prev); 429 prev->next = next; 430 } else 431 first_heap_area = next; 432 433 if (next != NULL) { 434 area_check(next); 435 next->prev = prev; 436 } else 437 last_heap_area = prev; 438 439 as_area_destroy(area->start); 440 } else if (shrink_size >= SHRINK_GRANULARITY) { 441 /* 442 * Make sure that we always shrink the area 443 * by a multiple of page size and update 444 * the block layout accordingly. 445 */ 446 447 size_t asize = (size_t) (area->end - area->start) - shrink_size; 448 void *end = (void *) ((uintptr_t) area->start + asize); 449 450 /* Resize the address space area */ 451 int ret = as_area_resize(area->start, asize, 0); 452 if (ret != EOK) 453 abort(); 454 455 /* Update heap area parameters */ 456 area->end = end; 457 458 /* Update block layout */ 459 void *last = (void *) last_head; 460 size_t excess = (size_t) (area->end - last); 461 462 if (excess > 0) { 463 if (excess >= STRUCT_OVERHEAD) { 464 /* 465 * The previous block cannot be free and there 466 * is enough free space left in the area to 467 * create a new free block. 468 */ 469 block_init(last, excess, true, area); 470 } else { 471 /* 472 * The excess is small. Therefore just enlarge 473 * the previous block. 474 */ 475 heap_block_foot_t *prev_foot = (heap_block_foot_t *) 476 (((uintptr_t) last_head) - sizeof(heap_block_foot_t)); 477 heap_block_head_t *prev_head = BLOCK_HEAD(prev_foot); 478 479 block_check((void *) prev_head); 480 481 block_init(prev_head, prev_head->size + excess, 482 prev_head->free, area); 483 } 484 } 485 } 486 } 487 337 488 next = NULL; 338 489 } … … 362 513 static void split_mark(heap_block_head_t *cur, const size_t size) 363 514 { 364 assert(cur->size >= size);515 malloc_assert(cur->size >= size); 365 516 366 517 /* See if we should split the block. */ … … 398 549 { 399 550 area_check((void *) area); 400 assert((void *) first_block >= (void *) AREA_FIRST_BLOCK(area)); 401 assert((void *) first_block < area->end); 402 403 heap_block_head_t *cur; 404 for (cur = first_block; (void *) cur < area->end; 551 malloc_assert((void *) first_block >= (void *) AREA_FIRST_BLOCK_HEAD(area)); 552 malloc_assert((void *) first_block < area->end); 553 554 for (heap_block_head_t *cur = first_block; (void *) cur < area->end; 405 555 cur = (heap_block_head_t *) (((void *) cur) + cur->size)) { 406 556 block_check(cur); … … 436 586 * data in (including alignment). 437 587 */ 438 if ((void *) cur > (void *) AREA_FIRST_BLOCK (area)) {588 if ((void *) cur > (void *) AREA_FIRST_BLOCK_HEAD(area)) { 439 589 /* 440 590 * There is a block before the current block. … … 496 646 size_t reduced_size = cur->size - excess; 497 647 cur = (heap_block_head_t *) 498 (AREA_FIRST_BLOCK (area) + excess);648 (AREA_FIRST_BLOCK_HEAD(area) + excess); 499 649 500 block_init((void *) AREA_FIRST_BLOCK (area), excess,501 true, area);650 block_init((void *) AREA_FIRST_BLOCK_HEAD(area), 651 excess, true, area); 502 652 block_init(cur, reduced_size, true, area); 503 653 split_mark(cur, real_size); … … 527 677 static void *malloc_internal(const size_t size, const size_t align) 528 678 { 529 assert(first_heap_area != NULL);679 malloc_assert(first_heap_area != NULL); 530 680 531 681 if (align == 0) … … 552 702 553 703 /* Search the entire heap */ 554 heap_area_t *area;555 for (area = first_heap_area; area != NULL;area = area->next) {704 for (heap_area_t *area = first_heap_area; area != NULL; 705 area = area->next) { 556 706 heap_block_head_t *first = (heap_block_head_t *) 557 AREA_FIRST_BLOCK (area);707 AREA_FIRST_BLOCK_HEAD(area); 558 708 559 709 void *addr = malloc_area(area, first, split, real_size, … … 652 802 653 803 block_check(head); 654 assert(!head->free);804 malloc_assert(!head->free); 655 805 656 806 heap_area_t *area = head->area; 657 807 658 808 area_check(area); 659 assert((void *) head >= (void *) AREA_FIRST_BLOCK(area));660 assert((void *) head < area->end);809 malloc_assert((void *) head >= (void *) AREA_FIRST_BLOCK_HEAD(area)); 810 malloc_assert((void *) head < area->end); 661 811 662 812 void *ptr = NULL; … … 675 825 block_init((void *) head + real_size, 676 826 orig_size - real_size, true, area); 677 heap_shrink( );827 heap_shrink(area); 678 828 } 679 829 … … 729 879 730 880 block_check(head); 731 assert(!head->free);881 malloc_assert(!head->free); 732 882 733 883 heap_area_t *area = head->area; 734 884 735 885 area_check(area); 736 assert((void *) head >= (void *) AREA_FIRST_BLOCK(area));737 assert((void *) head < area->end);886 malloc_assert((void *) head >= (void *) AREA_FIRST_BLOCK_HEAD(area)); 887 malloc_assert((void *) head < area->end); 738 888 739 889 /* Mark the block itself as free. */ … … 751 901 752 902 /* Look at the previous block. If it is free, merge the two. */ 753 if ((void *) head > (void *) AREA_FIRST_BLOCK (area)) {903 if ((void *) head > (void *) AREA_FIRST_BLOCK_HEAD(area)) { 754 904 heap_block_foot_t *prev_foot = 755 905 (heap_block_foot_t *) (((void *) head) - sizeof(heap_block_foot_t)); … … 765 915 } 766 916 767 heap_shrink( );917 heap_shrink(area); 768 918 769 919 futex_up(&malloc_futex); 770 920 } 771 921 922 void *heap_check(void) 923 { 924 futex_down(&malloc_futex); 925 926 if (first_heap_area == NULL) { 927 futex_up(&malloc_futex); 928 return (void *) -1; 929 } 930 931 /* Walk all heap areas */ 932 for (heap_area_t *area = first_heap_area; area != NULL; 933 area = area->next) { 934 935 /* Check heap area consistency */ 936 if ((area->magic != HEAP_AREA_MAGIC) || 937 ((void *) area != area->start) || 938 (area->start >= area->end) || 939 (((uintptr_t) area->start % PAGE_SIZE) != 0) || 940 (((uintptr_t) area->end % PAGE_SIZE) != 0)) { 941 futex_up(&malloc_futex); 942 return (void *) area; 943 } 944 945 /* Walk all heap blocks */ 946 for (heap_block_head_t *head = (heap_block_head_t *) 947 AREA_FIRST_BLOCK_HEAD(area); (void *) head < area->end; 948 head = (heap_block_head_t *) (((void *) head) + head->size)) { 949 950 /* Check heap block consistency */ 951 if (head->magic != HEAP_BLOCK_HEAD_MAGIC) { 952 futex_up(&malloc_futex); 953 return (void *) head; 954 } 955 956 heap_block_foot_t *foot = BLOCK_FOOT(head); 957 958 if ((foot->magic != HEAP_BLOCK_FOOT_MAGIC) || 959 (head->size != foot->size)) { 960 futex_up(&malloc_futex); 961 return (void *) foot; 962 } 963 } 964 } 965 966 futex_up(&malloc_futex); 967 968 return NULL; 969 } 970 772 971 /** @} 773 972 */ -
uspace/lib/c/include/adt/list.h
r8d308b9 r9d47440 49 49 * 50 50 */ 51 #define LIST_INITIALIZE(name) link_t name = { \ 52 .prev = &name, \ 53 .next = &name \ 54 } 51 #define LIST_INITIALIZE(name) \ 52 link_t name = { \ 53 .prev = &name, \ 54 .next = &name \ 55 } 56 57 #define list_get_instance(link, type, member) \ 58 ((type *) (((void *)(link)) - ((void *) &(((type *) NULL)->member)))) 59 60 #define list_foreach(list, iterator) \ 61 for (link_t *iterator = (list).next; \ 62 iterator != &(list); iterator = iterator->next) 55 63 56 64 /** Initialize doubly-linked circular list link … … 71 79 * Initialize doubly-linked circular list. 72 80 * 73 * @param head Pointer to link_t structure representing head ofthe list.74 * 75 */ 76 static inline void list_initialize(link_t * head)77 { 78 head->prev = head;79 head->next = head;81 * @param list Pointer to link_t structure representing the list. 82 * 83 */ 84 static inline void list_initialize(link_t *list) 85 { 86 list->prev = list; 87 list->next = list; 80 88 } 81 89 … … 85 93 * 86 94 * @param link Pointer to link_t structure to be added. 87 * @param head Pointer to link_t structure representing head ofthe list.88 * 89 */ 90 static inline void list_prepend(link_t *link, link_t * head)91 { 92 link->next = head->next;93 link->prev = head;94 head->next->prev = link;95 head->next = link;95 * @param list Pointer to link_t structure representing the list. 96 * 97 */ 98 static inline void list_prepend(link_t *link, link_t *list) 99 { 100 link->next = list->next; 101 link->prev = list; 102 list->next->prev = link; 103 list->next = link; 96 104 } 97 105 … … 101 109 * 102 110 * @param link Pointer to link_t structure to be added. 103 * @param head Pointer to link_t structure representing head of the list. 104 * 105 */ 106 static inline void list_append(link_t *link, link_t *head) 107 { 108 link->prev = head->prev; 109 link->next = head; 110 head->prev->next = link; 111 head->prev = link; 112 } 113 114 /** Insert item before another item in doubly-linked circular list. */ 115 static inline void list_insert_before(link_t *l, link_t *r) 116 { 117 list_append(l, r); 118 } 119 120 /** Insert item after another item in doubly-linked circular list. */ 121 static inline void list_insert_after(link_t *r, link_t *l) 122 { 123 list_prepend(l, r); 111 * @param list Pointer to link_t structure representing the list. 112 * 113 */ 114 static inline void list_append(link_t *link, link_t *list) 115 { 116 link->prev = list->prev; 117 link->next = list; 118 list->prev->next = link; 119 list->prev = link; 120 } 121 122 /** Insert item before another item in doubly-linked circular list. 123 * 124 */ 125 static inline void list_insert_before(link_t *link, link_t *list) 126 { 127 list_append(link, list); 128 } 129 130 /** Insert item after another item in doubly-linked circular list. 131 * 132 */ 133 static inline void list_insert_after(link_t *link, link_t *list) 134 { 135 list_prepend(list, link); 124 136 } 125 137 … … 143 155 * Query emptiness of doubly-linked circular list. 144 156 * 145 * @param head Pointer to link_t structure representing head of the list. 146 * 147 */ 148 static inline int list_empty(link_t *head) 149 { 150 return ((head->next == head) ? 1 : 0); 157 * @param list Pointer to link_t structure representing the list. 158 * 159 */ 160 static inline int list_empty(link_t *list) 161 { 162 return (list->next == list); 163 } 164 165 /** Get head item of a list. 166 * 167 * @param list Pointer to link_t structure representing the list. 168 * 169 * @return Head item of the list. 170 * @return NULL if the list is empty. 171 * 172 */ 173 static inline link_t *list_head(link_t *list) 174 { 175 return ((list->next == list) ? NULL : list->next); 151 176 } 152 177 … … 205 230 } 206 231 207 #define list_get_instance(link, type, member) \ 208 ((type *) (((void *)(link)) - ((void *) &(((type *) NULL)->member)))) 209 210 #define list_foreach(list, iterator) \ 211 for (link_t *iterator = (list).next; \ 212 iterator != &(list); iterator = iterator->next) 232 /** Get n-th item of a list. 233 * 234 * @param list Pointer to link_t structure representing the list. 235 * @param n Item number (indexed from zero). 236 * 237 * @return n-th item of the list. 238 * @return NULL if no n-th item found. 239 * 240 */ 241 static inline link_t *list_nth(link_t *list, unsigned int n) 242 { 243 unsigned int cnt = 0; 244 245 list_foreach(*list, link) { 246 if (cnt == n) 247 return link; 248 249 cnt++; 250 } 251 252 return NULL; 253 } 213 254 214 255 extern int list_member(const link_t *, const link_t *); -
uspace/lib/c/include/as.h
r8d308b9 r9d47440 59 59 extern int as_area_destroy(void *); 60 60 extern void *set_maxheapsize(size_t); 61 extern void * as_get_mappable_page(size_t);61 extern void *as_get_mappable_page(size_t); 62 62 63 63 #endif -
uspace/lib/c/include/assert.h
r8d308b9 r9d47440 47 47 */ 48 48 49 #define STR(l) #l 50 #define STR2(l) STR(l) 51 49 52 #ifndef NDEBUG 50 53 … … 52 55 do { \ 53 56 if (!(expr)) \ 54 assert_abort(#expr, __FILE__, __LINE__); \57 assert_abort(#expr, __FILE__, STR2(__LINE__)); \ 55 58 } while (0) 56 59 … … 61 64 #endif /* NDEBUG */ 62 65 63 extern void assert_abort(const char *, const char *, unsigned int)66 extern void assert_abort(const char *, const char *, const char *) 64 67 __attribute__((noreturn)); 68 65 69 66 70 #endif -
uspace/lib/c/include/event.h
r8d308b9 r9d47440 39 39 40 40 extern int event_subscribe(event_type_t, sysarg_t); 41 extern int event_unmask(event_type_t); 41 42 42 43 #endif -
uspace/lib/c/include/malloc.h
r8d308b9 r9d47440 46 46 extern void *realloc(const void *addr, const size_t size); 47 47 extern void free(const void *addr); 48 extern void *heap_check(void); 48 49 49 50 #endif
Note:
See TracChangeset
for help on using the changeset viewer.
