/branches/dd/uspace/srv/kbd/ctl/pc.c |
---|
207,9 → 207,6 |
map = scanmap_e0; |
map_length = sizeof(scanmap_e0) / sizeof(int); |
break; |
default: |
map = NULL; |
map_length = 0; |
} |
ds = ds_s; |
221,7 → 218,7 |
type = KEY_PRESS; |
} |
if ((scancode < 0) || ((size_t) scancode >= map_length)) |
if (scancode < 0 || scancode >= map_length) |
return; |
key = map[scancode]; |
/branches/dd/uspace/srv/kbd/genarch/gsp.c |
---|
244,7 → 244,7 |
key[0] = t->old_state; |
key[1] = t->input; |
hash_table_insert(&p->trans, key, &t->link); |
hash_table_insert(&p->trans, &key, &t->link); |
} |
/** Allocate transition structure. */ |
276,8 → 276,7 |
gsp_trans_t *t; |
t = hash_table_get_instance(item, gsp_trans_t, link); |
return ((key[0] == (unsigned long) t->old_state) |
&& (key[1] == (unsigned long) t->input)); |
return (key[0] == t->old_state && key[1] == t->input); |
} |
static void trans_op_remove_callback(link_t *item) |
/branches/dd/uspace/srv/kbd/layout/us_qwerty.c |
---|
27,7 → 27,7 |
*/ |
/** @addtogroup kbd |
* @brief US QWERTY layout. |
* @brief US QWERTY leyout. |
* @{ |
*/ |
/branches/dd/uspace/srv/kbd/layout/cz.c |
---|
27,7 → 27,7 |
*/ |
/** @addtogroup kbd |
* @brief Czech QWERTZ layout. |
* @brief US QWERTY leyout. |
* @{ |
*/ |
399,8 → 399,6 |
case ms_carka: |
return parse_ms_carka(ev); |
} |
return 0; |
} |
/** |
/branches/dd/uspace/srv/kbd/port/i8042.c |
---|
135,8 → 135,8 |
(void) pio_read_8(&i8042->data); |
/* Enable kbd */ |
i8042_kbd.cmds[0].addr = (void *) &((i8042_t *) i8042_kernel)->status; |
i8042_kbd.cmds[3].addr = (void *) &((i8042_t *) i8042_kernel)->data; |
i8042_kbd.cmds[0].addr = &((i8042_t *) i8042_kernel)->status; |
i8042_kbd.cmds[3].addr = &((i8042_t *) i8042_kernel)->data; |
ipc_register_irq(sysinfo_value("kbd.inr"), device_assign_devno(), 0, &i8042_kbd); |
int newcontrol = i8042_KBD_IE | i8042_KBD_TRANSLATE; |
/branches/dd/uspace/srv/ns/ns.c |
---|
108,6 → 108,13 |
task_id_t id; |
ipcarg_t retval; |
if (callid & IPC_CALLID_NOTIFICATION) { |
id = (task_id_t) |
MERGE_LOUP32(IPC_GET_ARG2(call), IPC_GET_ARG3(call)); |
wait_notification((wait_type_t) IPC_GET_ARG1(call), id); |
continue; |
} |
switch (IPC_GET_METHOD(call)) { |
case IPC_M_SHARE_IN: |
switch (IPC_GET_ARG3(call)) { |
126,7 → 133,7 |
} |
continue; |
case IPC_M_PHONE_HUNGUP: |
retval = ns_task_disconnect(&call); |
retval = EOK; |
break; |
case IPC_M_CONNECT_TO_ME: |
/* |
163,12 → 170,6 |
MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call)); |
wait_for_task(id, &call, callid); |
continue; |
case NS_ID_INTRO: |
retval = ns_task_id_intro(&call); |
break; |
case NS_RETVAL: |
retval = ns_task_retval(&call); |
break; |
default: |
retval = ENOENT; |
break; |
/branches/dd/uspace/srv/ns/task.c |
---|
1,6 → 1,5 |
/* |
* Copyright (c) 2009 Martin Decky |
* Copyright (c) 2009 Jiri Svoboda |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
42,13 → 41,20 |
#include "ns.h" |
#define TASK_HASH_TABLE_CHAINS 256 |
#define P2I_HASH_TABLE_CHAINS 256 |
static int get_id_by_phone(ipcarg_t phone_hash, task_id_t *id); |
/* TODO: |
* |
* As there is currently no convention that each task has to be waited |
* The current implementation of waiting on a task is not perfect. If somebody |
* wants to wait on a task which has already finished before the NS asked |
* the kernel to receive notifications, it would block indefinitively. |
* |
* A solution to this is to fail immediately on a task for which no creation |
* notification was received yet. However, there is a danger of a race condition |
* in this solution -- the caller has to make sure that it is not trying to wait |
* before the NS has a change to receive the task creation notification. This |
* can be assured by waiting for this event in task_spawn(). |
* |
* Finally, as there is currently no convention that each task has to be waited |
* for, the NS can leak memory because of the zombie tasks. |
* |
*/ |
56,10 → 62,8 |
/** Task hash table item. */ |
typedef struct { |
link_t link; |
task_id_t id; /**< Task ID. */ |
bool finished; /**< Task is done. */ |
bool have_rval; /**< Task returned a value. */ |
int retval; /**< The return value. */ |
task_id_t id; /**< Task ID. */ |
bool destroyed; |
} hashed_task_t; |
/** Compute hash index into task hash table. |
79,7 → 83,7 |
/** Compare a key with hashed item. |
* |
* @param key Array of keys. |
* @param keys Must be less than or equal to 2. |
* @param keys Must be lesser or equal to 2. |
* @param item Pointer to a hash table item. |
* |
* @return Non-zero if the key matches the item, zero otherwise. |
121,65 → 125,6 |
/** Task hash table structure. */ |
static hash_table_t task_hash_table; |
typedef struct { |
link_t link; |
ipcarg_t phash; /**< Task ID. */ |
task_id_t id; /**< Task ID. */ |
} p2i_entry_t; |
/** Compute hash index into task hash table. |
* |
* @param key Array of keys. |
* @return Hash index corresponding to key[0]. |
* |
*/ |
static hash_index_t p2i_hash(unsigned long *key) |
{ |
assert(key); |
return (*key % TASK_HASH_TABLE_CHAINS); |
} |
/** Compare a key with hashed item. |
* |
* @param key Array of keys. |
* @param keys Must be less than or equal to 1. |
* @param item Pointer to a hash table item. |
* |
* @return Non-zero if the key matches the item, zero otherwise. |
* |
*/ |
static int p2i_compare(unsigned long key[], hash_count_t keys, link_t *item) |
{ |
assert(key); |
assert(keys == 1); |
assert(item); |
p2i_entry_t *e = hash_table_get_instance(item, p2i_entry_t, link); |
return (key[0] == e->phash); |
} |
/** Perform actions after removal of item from the hash table. |
* |
* @param item Item that was removed from the hash table. |
* |
*/ |
static void p2i_remove(link_t *item) |
{ |
assert(item); |
free(hash_table_get_instance(item, p2i_entry_t, link)); |
} |
/** Operations for task hash table. */ |
static hash_table_operations_t p2i_ops = { |
.hash = p2i_hash, |
.compare = p2i_compare, |
.remove_callback = p2i_remove |
}; |
/** Map phone hash to task ID */ |
static hash_table_t phone_to_id; |
/** Pending task wait structure. */ |
typedef struct { |
link_t link; |
196,13 → 141,10 |
printf(NAME ": No memory available for tasks\n"); |
return ENOMEM; |
} |
if (!hash_table_create(&phone_to_id, P2I_HASH_TABLE_CHAINS, |
1, &p2i_ops)) { |
printf(NAME ": No memory available for tasks\n"); |
return ENOMEM; |
} |
if (event_subscribe(EVENT_WAIT, 0) != EOK) |
printf(NAME ": Error registering wait notifications\n"); |
list_initialize(&pending_wait); |
return EOK; |
212,7 → 154,6 |
void process_pending_wait(void) |
{ |
link_t *cur; |
task_exit_t texit; |
loop: |
for (cur = pending_wait.next; cur != &pending_wait; cur = cur->next) { |
228,16 → 169,12 |
continue; |
hashed_task_t *ht = hash_table_get_instance(link, hashed_task_t, link); |
if (!ht->finished) |
if (!ht->destroyed) |
continue; |
if (!(pr->callid & IPC_CALLID_NOTIFICATION)) { |
texit = ht->have_rval ? TASK_EXIT_NORMAL : |
TASK_EXIT_UNEXPECTED; |
ipc_answer_2(pr->callid, EOK, texit, |
ht->retval); |
} |
if (!(pr->callid & IPC_CALLID_NOTIFICATION)) |
ipc_answer_0(pr->callid, EOK); |
hash_table_remove(&task_hash_table, keys, 2); |
list_remove(cur); |
free(pr); |
245,27 → 182,66 |
} |
} |
static void fail_pending_wait(task_id_t id, int rc) |
{ |
link_t *cur; |
loop: |
for (cur = pending_wait.next; cur != &pending_wait; cur = cur->next) { |
pending_wait_t *pr = list_get_instance(cur, pending_wait_t, link); |
if (pr->id == id) { |
if (!(pr->callid & IPC_CALLID_NOTIFICATION)) |
ipc_answer_0(pr->callid, rc); |
list_remove(cur); |
free(pr); |
goto loop; |
} |
} |
} |
void wait_notification(wait_type_t et, task_id_t id) |
{ |
unsigned long keys[2] = { |
LOWER32(id), |
UPPER32(id) |
}; |
link_t *link = hash_table_find(&task_hash_table, keys); |
if (link == NULL) { |
hashed_task_t *ht = |
(hashed_task_t *) malloc(sizeof(hashed_task_t)); |
if (ht == NULL) { |
fail_pending_wait(id, ENOMEM); |
return; |
} |
link_initialize(&ht->link); |
ht->id = id; |
ht->destroyed = (et == TASK_CREATE) ? false : true; |
hash_table_insert(&task_hash_table, keys, &ht->link); |
} else { |
hashed_task_t *ht = |
hash_table_get_instance(link, hashed_task_t, link); |
ht->destroyed = (et == TASK_CREATE) ? false : true; |
} |
} |
void wait_for_task(task_id_t id, ipc_call_t *call, ipc_callid_t callid) |
{ |
ipcarg_t retval; |
task_exit_t texit; |
unsigned long keys[2] = { |
LOWER32(id), |
UPPER32(id) |
}; |
link_t *link = hash_table_find(&task_hash_table, keys); |
hashed_task_t *ht = (link != NULL) ? |
hash_table_get_instance(link, hashed_task_t, link) : NULL; |
if (ht == NULL) { |
/* No such task exists. */ |
retval = ENOENT; |
goto out; |
} |
if (!ht->finished) { |
if ((ht == NULL) || (!ht->destroyed)) { |
/* Add to pending list */ |
pending_wait_t *pr = |
(pending_wait_t *) malloc(sizeof(pending_wait_t)); |
284,131 → 260,10 |
retval = EOK; |
out: |
if (!(callid & IPC_CALLID_NOTIFICATION)) { |
texit = ht->have_rval ? TASK_EXIT_NORMAL : TASK_EXIT_UNEXPECTED; |
ipc_answer_2(callid, retval, texit, ht->retval); |
} |
if (!(callid & IPC_CALLID_NOTIFICATION)) |
ipc_answer_0(callid, retval); |
} |
int ns_task_id_intro(ipc_call_t *call) |
{ |
task_id_t id; |
unsigned long keys[2]; |
link_t *link; |
p2i_entry_t *e; |
hashed_task_t *ht; |
id = MERGE_LOUP32(IPC_GET_ARG1(*call), IPC_GET_ARG2(*call)); |
keys[0] = call->in_phone_hash; |
link = hash_table_find(&phone_to_id, keys); |
if (link != NULL) |
return EEXISTS; |
e = (p2i_entry_t *) malloc(sizeof(p2i_entry_t)); |
if (e == NULL) |
return ENOMEM; |
ht = (hashed_task_t *) malloc(sizeof(hashed_task_t)); |
if (ht == NULL) |
return ENOMEM; |
/* Insert to phone-to-id map. */ |
link_initialize(&e->link); |
e->phash = call->in_phone_hash; |
e->id = id; |
hash_table_insert(&phone_to_id, keys, &e->link); |
/* Insert to main table. */ |
keys[0] = LOWER32(id); |
keys[1] = UPPER32(id); |
link_initialize(&ht->link); |
ht->id = id; |
ht->finished = false; |
ht->have_rval = false; |
ht->retval = -1; |
hash_table_insert(&task_hash_table, keys, &ht->link); |
return EOK; |
} |
int ns_task_retval(ipc_call_t *call) |
{ |
task_id_t id; |
unsigned long keys[2]; |
int rc; |
rc = get_id_by_phone(call->in_phone_hash, &id); |
if (rc != EOK) |
return rc; |
keys[0] = LOWER32(id); |
keys[1] = UPPER32(id); |
link_t *link = hash_table_find(&task_hash_table, keys); |
hashed_task_t *ht = (link != NULL) ? |
hash_table_get_instance(link, hashed_task_t, link) : NULL; |
if ((ht == NULL) || ht->finished) |
return EINVAL; |
ht->finished = true; |
ht->have_rval = true; |
ht->retval = IPC_GET_ARG1(*call); |
return EOK; |
} |
int ns_task_disconnect(ipc_call_t *call) |
{ |
unsigned long keys[2]; |
task_id_t id; |
int rc; |
rc = get_id_by_phone(call->in_phone_hash, &id); |
if (rc != EOK) |
return rc; |
/* Delete from phone-to-id map. */ |
keys[0] = call->in_phone_hash; |
hash_table_remove(&phone_to_id, keys, 1); |
/* Mark task as finished. */ |
keys[0] = LOWER32(id); |
keys[1] = UPPER32(id); |
link_t *link = hash_table_find(&task_hash_table, keys); |
hashed_task_t *ht = |
hash_table_get_instance(link, hashed_task_t, link); |
if (ht == NULL) |
return EOK; |
ht->finished = true; |
return EOK; |
} |
static int get_id_by_phone(ipcarg_t phone_hash, task_id_t *id) |
{ |
unsigned long keys[1]; |
link_t *link; |
p2i_entry_t *e; |
keys[0] = phone_hash; |
link = hash_table_find(&phone_to_id, keys); |
if (link == NULL) |
return ENOENT; |
e = hash_table_get_instance(link, p2i_entry_t, link); |
*id = e->id; |
return EOK; |
} |
/** |
* @} |
*/ |
/branches/dd/uspace/srv/ns/task.h |
---|
42,11 → 42,6 |
extern void wait_notification(wait_type_t et, task_id_t id); |
extern void wait_for_task(task_id_t id, ipc_call_t *call, ipc_callid_t callid); |
extern int ns_task_id_intro(ipc_call_t *call); |
extern int ns_task_disconnect(ipc_call_t *call); |
extern int ns_task_retval(ipc_call_t *call); |
#endif |
/** |
/branches/dd/uspace/srv/console/screenbuffer.h |
---|
135,8 → 135,6 |
return (a1.a.r.fg_color == a2.a.r.fg_color) |
&& (a1.a.r.bg_color == a2.a.r.bg_color); |
} |
return 0; |
} |
/branches/dd/uspace/srv/console/console.c |
---|
51,7 → 51,6 |
#include <sysinfo.h> |
#include <event.h> |
#include <devmap.h> |
#include <fibril_sync.h> |
#include "console.h" |
#include "gcons.h" |
69,7 → 68,6 |
int phone; /**< Framebuffer phone */ |
ipcarg_t cols; /**< Framebuffer columns */ |
ipcarg_t rows; /**< Framebuffer rows */ |
int color_cap; /**< Color capabilities (FB_CCAP_xxx) */ |
} fb_info; |
typedef struct { |
99,9 → 97,64 |
size_t cnt; /**< Width of the span. */ |
} fb_pending; |
static FIBRIL_MUTEX_INITIALIZE(input_mutex); |
static FIBRIL_CONDVAR_INITIALIZE(input_cv); |
/** Pending input structure. */ |
typedef struct { |
link_t link; |
console_t *cons; /**< Console waiting for input */ |
ipc_callid_t rid; /**< Call ID waiting for input */ |
ipc_callid_t callid; /**< Call ID waiting for IPC_DATA_READ */ |
size_t pos; /**< Position of the last stored data */ |
size_t size; /**< Size of ther buffer */ |
char *data; /**< Already stored data */ |
} pending_input_t; |
LIST_INITIALIZE(pending_input); |
/** Process pending input requests */ |
static void process_pending_input(void) |
{ |
async_serialize_start(); |
link_t *cur; |
loop: |
for (cur = pending_input.next; cur != &pending_input; cur = cur->next) { |
pending_input_t *pr = list_get_instance(cur, pending_input_t, link); |
console_event_t ev; |
if (keybuffer_pop(&pr->cons->keybuffer, &ev)) { |
if (pr->data != NULL) { |
if (ev.type == KEY_PRESS) { |
pr->data[pr->pos] = ev.c; |
pr->pos++; |
} |
} else { |
ipc_answer_4(pr->rid, EOK, ev.type, ev.key, ev.mods, ev.c); |
list_remove(cur); |
free(pr); |
goto loop; |
} |
} |
if ((pr->data != NULL) && (pr->pos == pr->size)) { |
(void) ipc_data_read_finalize(pr->callid, pr->data, pr->size); |
ipc_answer_1(pr->rid, EOK, pr->size); |
free(pr->data); |
list_remove(cur); |
free(pr); |
goto loop; |
} |
} |
async_serialize_end(); |
} |
static void curs_visibility(bool visible) |
{ |
async_msg_1(fb_info.phone, FB_CURSOR_VISIBILITY, visible); |
173,19 → 226,6 |
} |
} |
int ccap_fb_to_con(int ccap_fb, int *ccap_con) |
{ |
switch (ccap_fb) { |
case FB_CCAP_NONE: *ccap_con = CONSOLE_CCAP_NONE; break; |
case FB_CCAP_STYLE: *ccap_con = CONSOLE_CCAP_STYLE; break; |
case FB_CCAP_INDEXED: *ccap_con = CONSOLE_CCAP_INDEXED; break; |
case FB_CCAP_RGB: *ccap_con = CONSOLE_CCAP_RGB; break; |
default: return EINVAL; |
} |
return EOK; |
} |
/** Send an area of screenbuffer to the FB driver. */ |
static void fb_update_area(console_t *cons, ipcarg_t x0, ipcarg_t y0, ipcarg_t width, ipcarg_t height) |
{ |
247,12 → 287,9 |
/** Process a character from the client (TTY emulation). */ |
static void write_char(console_t *cons, wchar_t ch) |
{ |
bool flush_cursor = false; |
switch (ch) { |
case '\n': |
fb_pending_flush(); |
flush_cursor = true; |
cons->scr.position_y++; |
cons->scr.position_x = 0; |
break; |
278,10 → 315,8 |
cons->scr.position_x++; |
} |
if (cons->scr.position_x >= cons->scr.size_x) { |
flush_cursor = true; |
if (cons->scr.position_x >= cons->scr.size_x) |
cons->scr.position_y++; |
} |
if (cons->scr.position_y >= cons->scr.size_y) { |
fb_pending_flush(); |
292,9 → 327,7 |
if (cons == active_console) |
async_msg_1(fb_info.phone, FB_SCROLL, 1); |
} |
if (cons == active_console && flush_cursor) |
curs_goto(cons->scr.position_x, cons->scr.position_y); |
cons->scr.position_x = cons->scr.position_x % cons->scr.size_x; |
} |
413,10 → 446,7 |
break; |
} |
fibril_mutex_lock(&input_mutex); |
keybuffer_push(&active_console->keybuffer, &ev); |
fibril_condvar_broadcast(&input_cv); |
fibril_mutex_unlock(&input_mutex); |
break; |
default: |
retval = ENOENT; |
452,6 → 482,9 |
write_char(cons, ch); |
} |
if (cons == active_console) |
curs_goto(cons->scr.position_x, cons->scr.position_y); |
async_serialize_end(); |
gcons_notify_char(cons->index); |
477,10 → 510,10 |
return; |
} |
async_serialize_start(); |
size_t pos = 0; |
console_event_t ev; |
fibril_mutex_lock(&input_mutex); |
recheck: |
while ((keybuffer_pop(&cons->keybuffer, &ev)) && (pos < size)) { |
if (ev.type == KEY_PRESS) { |
buf[pos] = ev.c; |
493,25 → 526,50 |
ipc_answer_1(rid, EOK, size); |
free(buf); |
} else { |
fibril_condvar_wait(&input_cv, &input_mutex); |
goto recheck; |
pending_input_t *pr = (pending_input_t *) malloc(sizeof(pending_input_t)); |
if (!pr) { |
ipc_answer_0(callid, ENOMEM); |
ipc_answer_0(rid, ENOMEM); |
free(buf); |
async_serialize_end(); |
return; |
} |
pr->cons = cons; |
pr->rid = rid; |
pr->callid = callid; |
pr->pos = pos; |
pr->size = size; |
pr->data = buf; |
list_append(&pr->link, &pending_input); |
} |
fibril_mutex_unlock(&input_mutex); |
async_serialize_end(); |
} |
static void cons_get_event(console_t *cons, ipc_callid_t rid, ipc_call_t *request) |
{ |
async_serialize_start(); |
console_event_t ev; |
fibril_mutex_lock(&input_mutex); |
recheck: |
if (keybuffer_pop(&cons->keybuffer, &ev)) { |
ipc_answer_4(rid, EOK, ev.type, ev.key, ev.mods, ev.c); |
} else { |
fibril_condvar_wait(&input_cv, &input_mutex); |
goto recheck; |
pending_input_t *pr = (pending_input_t *) malloc(sizeof(pending_input_t)); |
if (!pr) { |
ipc_answer_0(rid, ENOMEM); |
async_serialize_end(); |
return; |
} |
pr->cons = cons; |
pr->rid = rid; |
pr->callid = 0; |
pr->data = NULL; |
list_append(&pr->link, &pending_input); |
} |
fibril_mutex_unlock(&input_mutex); |
async_serialize_end(); |
} |
/** Default thread for new connections */ |
540,9 → 598,6 |
ipcarg_t arg1; |
ipcarg_t arg2; |
ipcarg_t arg3; |
int cons_ccap; |
int rc; |
async_serialize_start(); |
if (cons->refcount == 0) |
568,17 → 623,17 |
if (cons->refcount == 0) |
gcons_notify_disconnect(cons->index); |
return; |
case VFS_OUT_READ: |
case VFS_READ: |
async_serialize_end(); |
cons_read(cons, callid, &call); |
async_serialize_start(); |
continue; |
case VFS_OUT_WRITE: |
case VFS_WRITE: |
async_serialize_end(); |
cons_write(cons, callid, &call); |
async_serialize_start(); |
continue; |
case VFS_OUT_SYNC: |
case VFS_SYNC: |
fb_pending_flush(); |
if (cons == active_console) { |
async_req_0_0(fb_info.phone, FB_FLUSH); |
605,14 → 660,6 |
arg1 = fb_info.cols; |
arg2 = fb_info.rows; |
break; |
case CONSOLE_GET_COLOR_CAP: |
rc = ccap_fb_to_con(fb_info.color_cap, &cons_ccap); |
if (rc != EOK) { |
ipc_answer_0(callid, rc); |
continue; |
} |
arg1 = cons_ccap; |
break; |
case CONSOLE_SET_STYLE: |
fb_pending_flush(); |
arg1 = IPC_GET_ARG1(call); |
664,12 → 711,13 |
static bool console_init(void) |
{ |
ipcarg_t color_cap; |
async_serialize_start(); |
/* Connect to keyboard driver */ |
kbd_phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_KEYBOARD, 0, 0); |
if (kbd_phone < 0) { |
printf(NAME ": Failed to connect to keyboard service\n"); |
async_serialize_end(); |
return false; |
} |
676,15 → 724,18 |
ipcarg_t phonehash; |
if (ipc_connect_to_me(kbd_phone, SERVICE_CONSOLE, 0, 0, &phonehash) != 0) { |
printf(NAME ": Failed to create callback from keyboard service\n"); |
async_serialize_end(); |
return false; |
} |
async_set_pending(process_pending_input); |
async_new_connection(phonehash, 0, NULL, keyboard_events); |
/* Connect to framebuffer driver */ |
fb_info.phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_VIDEO, 0, 0); |
if (fb_info.phone < 0) { |
printf(NAME ": Failed to connect to video service\n"); |
async_serialize_end(); |
return -1; |
} |
692,6 → 743,7 |
int rc = devmap_driver_register(NAME, client_connection); |
if (rc < 0) { |
printf(NAME ": Unable to register driver (%d)\n", rc); |
async_serialize_end(); |
return false; |
} |
701,8 → 753,6 |
/* Synchronize, the gcons could put something in queue */ |
async_req_0_0(fb_info.phone, FB_FLUSH); |
async_req_0_2(fb_info.phone, FB_GET_CSIZE, &fb_info.cols, &fb_info.rows); |
async_req_0_1(fb_info.phone, FB_GET_COLOR_CAP, &color_cap); |
fb_info.color_cap = color_cap; |
/* Set up shared memory buffer. */ |
size_t ib_size = sizeof(keyfield_t) * fb_info.cols * fb_info.rows; |
729,6 → 779,7 |
if (screenbuffer_init(&consoles[i].scr, |
fb_info.cols, fb_info.rows) == NULL) { |
printf(NAME ": Unable to allocate screen buffer %u\n", i); |
async_serialize_end(); |
return false; |
} |
screenbuffer_clear(&consoles[i].scr); |
742,6 → 793,7 |
if (devmap_device_register(vc, &consoles[i].dev_handle) != EOK) { |
devmap_hangup_phone(DEVMAP_DRIVER); |
printf(NAME ": Unable to register device %s\n", vc); |
async_serialize_end(); |
return false; |
} |
} |
751,13 → 803,11 |
__SYSCALL0(SYS_DEBUG_DISABLE_CONSOLE); |
/* Initialize the screen */ |
async_serialize_start(); |
gcons_redraw_console(); |
set_rgb_color(DEFAULT_FOREGROUND, DEFAULT_BACKGROUND); |
screen_clear(); |
curs_goto(0, 0); |
curs_visibility(active_console->scr.is_cursor_visible); |
async_serialize_end(); |
/* Receive kernel notifications */ |
if (event_subscribe(EVENT_KCONSOLE, 0) != EOK) |
765,6 → 815,7 |
async_set_interrupt_received(interrupt_received); |
async_serialize_end(); |
return true; |
} |
/branches/dd/uspace/srv/bd/file_bd/file_bd.c |
---|
44,12 → 44,11 |
#include <ipc/bd.h> |
#include <async.h> |
#include <as.h> |
#include <fibril_sync.h> |
#include <futex.h> |
#include <devmap.h> |
#include <sys/types.h> |
#include <errno.h> |
#include <bool.h> |
#include <task.h> |
#define NAME "file_bd" |
57,12 → 56,12 |
static FILE *img; |
static dev_handle_t dev_handle; |
static fibril_mutex_t dev_lock; |
static atomic_t dev_futex = FUTEX_INITIALIZER; |
static int file_bd_init(const char *fname); |
static void file_bd_connection(ipc_callid_t iid, ipc_call_t *icall); |
static int file_bd_read(off_t blk_idx, size_t size, void *buf); |
static int file_bd_write(off_t blk_idx, size_t size, void *buf); |
static int file_bd_read(off_t blk_idx, off_t size, void *buf); |
static int file_bd_write(off_t blk_idx, off_t size, void *buf); |
int main(int argc, char **argv) |
{ |
87,7 → 86,6 |
} |
printf(NAME ": Accepting connections\n"); |
task_retval(0); |
async_manager(); |
/* Not reached */ |
108,8 → 106,6 |
if (img == NULL) |
return EINVAL; |
fibril_mutex_initialize(&dev_lock); |
return EOK; |
} |
122,7 → 118,7 |
int flags; |
int retval; |
off_t idx; |
size_t size; |
off_t size; |
/* Answer the IPC_M_CONNECT_ME_TO call. */ |
ipc_answer_0(iid, EOK); |
169,21 → 165,27 |
} |
} |
static int file_bd_read(off_t blk_idx, size_t size, void *buf) |
static int file_bd_read(off_t blk_idx, off_t size, void *buf) |
{ |
size_t n_rd; |
fibril_mutex_lock(&dev_lock); |
printf("file_bd_read\n"); |
futex_down(&dev_futex); |
printf("seek\n"); |
fseek(img, blk_idx * size, SEEK_SET); |
printf("read\n"); |
n_rd = fread(buf, 1, size, img); |
printf("done\n"); |
printf("done\n"); |
if (ferror(img)) { |
fibril_mutex_unlock(&dev_lock); |
futex_up(&dev_futex); |
return EIO; /* Read error */ |
} |
fibril_mutex_unlock(&dev_lock); |
futex_up(&dev_futex); |
if (n_rd < size) |
return EINVAL; /* Read beyond end of disk */ |
191,21 → 193,21 |
return EOK; |
} |
static int file_bd_write(off_t blk_idx, size_t size, void *buf) |
static int file_bd_write(off_t blk_idx, off_t size, void *buf) |
{ |
size_t n_wr; |
fibril_mutex_lock(&dev_lock); |
futex_down(&dev_futex); |
fseek(img, blk_idx * size, SEEK_SET); |
n_wr = fread(buf, 1, size, img); |
if (ferror(img) || n_wr < size) { |
fibril_mutex_unlock(&dev_lock); |
futex_up(&dev_futex); |
return EIO; /* Write error */ |
} |
fibril_mutex_unlock(&dev_lock); |
futex_up(&dev_futex); |
return EOK; |
} |
/branches/dd/uspace/srv/bd/gxe_bd/gxe_bd.c |
---|
42,11 → 42,10 |
#include <ipc/bd.h> |
#include <async.h> |
#include <as.h> |
#include <fibril_sync.h> |
#include <futex.h> |
#include <devmap.h> |
#include <sys/types.h> |
#include <errno.h> |
#include <task.h> |
#define NAME "gxe_bd" |
92,11 → 91,11 |
static dev_handle_t dev_handle[MAX_DISKS]; |
static fibril_mutex_t dev_lock[MAX_DISKS]; |
static atomic_t dev_futex = FUTEX_INITIALIZER; |
static int gxe_bd_init(void); |
static void gxe_bd_connection(ipc_callid_t iid, ipc_call_t *icall); |
static int gx_bd_rdwr(int disk_id, ipcarg_t method, off_t offset, size_t size, |
static int gx_bd_rdwr(int disk_id, ipcarg_t method, off_t offset, off_t size, |
void *buf); |
static int gxe_bd_read_block(int disk_id, uint64_t offset, size_t size, |
void *buf); |
111,7 → 110,6 |
return -1; |
printf(NAME ": Accepting connections\n"); |
task_retval(0); |
async_manager(); |
/* Not reached */ |
147,7 → 145,6 |
name); |
return rc; |
} |
fibril_mutex_initialize(&dev_lock[i]); |
} |
return EOK; |
163,7 → 160,7 |
int flags; |
int retval; |
off_t idx; |
size_t size; |
off_t size; |
int disk_id, i; |
/* Get the device handle. */ |
223,7 → 220,7 |
} |
} |
static int gx_bd_rdwr(int disk_id, ipcarg_t method, off_t offset, size_t size, |
static int gx_bd_rdwr(int disk_id, ipcarg_t method, off_t offset, off_t size, |
void *buf) |
{ |
int rc; |
259,7 → 256,7 |
size_t i; |
uint32_t w; |
fibril_mutex_lock(&dev_lock[disk_id]); |
futex_down(&dev_futex); |
pio_write_32(&dev->offset_lo, (uint32_t) offset); |
pio_write_32(&dev->offset_hi, offset >> 32); |
pio_write_32(&dev->disk_id, disk_id); |
267,7 → 264,6 |
status = pio_read_32(&dev->status); |
if (status == STATUS_FAILURE) { |
fibril_mutex_unlock(&dev_lock[disk_id]); |
return EIO; |
} |
275,7 → 271,7 |
((uint8_t *) buf)[i] = w = pio_read_8(&dev->buffer[i]); |
} |
fibril_mutex_unlock(&dev_lock[disk_id]); |
futex_up(&dev_futex); |
return EOK; |
} |
289,7 → 285,7 |
pio_write_8(&dev->buffer[i], ((const uint8_t *) buf)[i]); |
} |
fibril_mutex_lock(&dev_lock[disk_id]); |
futex_down(&dev_futex); |
pio_write_32(&dev->offset_lo, (uint32_t) offset); |
pio_write_32(&dev->offset_hi, offset >> 32); |
pio_write_32(&dev->disk_id, disk_id); |
297,11 → 293,10 |
status = pio_read_32(&dev->status); |
if (status == STATUS_FAILURE) { |
fibril_mutex_unlock(&dev_lock[disk_id]); |
return EIO; |
} |
fibril_mutex_unlock(&dev_lock[disk_id]); |
futex_up(&dev_futex); |
return EOK; |
} |
/branches/dd/uspace/srv/bd/ata_bd/ata_bd.c |
---|
37,9 → 37,6 |
* This driver currently works only with CHS addressing and uses PIO. |
* Currently based on the (now obsolete) ANSI X3.221-1994 (ATA-1) standard. |
* At this point only reading is possible, not writing. |
* |
* The driver services a single controller which can have up to two disks |
* attached. |
*/ |
#include <stdio.h> |
49,12 → 46,11 |
#include <ipc/bd.h> |
#include <async.h> |
#include <as.h> |
#include <fibril_sync.h> |
#include <futex.h> |
#include <devmap.h> |
#include <sys/types.h> |
#include <errno.h> |
#include <bool.h> |
#include <task.h> |
#include "ata_bd.h" |
68,12 → 64,15 |
static ata_cmd_t *cmd; |
static ata_ctl_t *ctl; |
/** Per-disk state. */ |
static dev_handle_t dev_handle[MAX_DISKS]; |
static atomic_t dev_futex = FUTEX_INITIALIZER; |
static disk_t disk[MAX_DISKS]; |
static int ata_bd_init(void); |
static void ata_bd_connection(ipc_callid_t iid, ipc_call_t *icall); |
static int ata_bd_rdwr(int disk_id, ipcarg_t method, off_t offset, size_t size, |
static int ata_bd_rdwr(int disk_id, ipcarg_t method, off_t offset, off_t size, |
void *buf); |
static int ata_bd_read_block(int disk_id, uint64_t blk_idx, size_t blk_cnt, |
void *buf); |
90,15 → 89,14 |
printf(NAME ": ATA disk driver\n"); |
printf("I/O address 0x%x\n", cmd_physical); |
printf("cmd_physical = 0x%x\n", cmd_physical); |
printf("ctl_physical = 0x%x\n", ctl_physical); |
if (ata_bd_init() != EOK) |
return -1; |
/* Put drives to reset, disable interrupts. */ |
printf("Reset drives... "); |
fflush(stdout); |
printf("Reset drives...\n"); |
pio_write_8(&ctl->device_control, DCR_SRST); |
/* FIXME: Find out how to do this properly. */ |
async_usleep(100); |
109,6 → 107,8 |
} while ((status & SR_BSY) != 0); |
printf("Done\n"); |
printf("Status = 0x%x\n", pio_read_8(&cmd->status)); |
(void) drive_identify(0, &disk[0]); |
(void) drive_identify(1, &disk[1]); |
120,7 → 120,7 |
continue; |
snprintf(name, 16, "disk%d", i); |
rc = devmap_device_register(name, &disk[i].dev_handle); |
rc = devmap_device_register(name, &dev_handle[i]); |
if (rc != EOK) { |
devmap_hangup_phone(DEVMAP_DRIVER); |
printf(NAME ": Unable to register device %s.\n", |
136,7 → 136,6 |
} |
printf(NAME ": Accepting connections\n"); |
task_retval(0); |
async_manager(); |
/* Not reached */ |
147,16 → 146,15 |
{ |
uint16_t data; |
uint8_t status; |
size_t i; |
int i; |
printf("Identify drive %d... ", disk_id); |
fflush(stdout); |
printf("Identify drive %d\n", disk_id); |
pio_write_8(&cmd->drive_head, ((disk_id != 0) ? DHR_DRV : 0)); |
async_usleep(100); |
pio_write_8(&cmd->command, CMD_IDENTIFY_DRIVE); |
status = pio_read_8(&cmd->status); |
printf("Status = 0x%x\n", status); |
d->present = false; |
183,6 → 181,8 |
} |
} |
printf("\n\nStatus = 0x%x\n", pio_read_8(&cmd->status)); |
d->blocks = d->cylinders * d->heads * d->sectors; |
printf("Geometry: %u cylinders, %u heads, %u sectors\n", |
189,7 → 189,6 |
d->cylinders, d->heads, d->sectors); |
d->present = true; |
fibril_mutex_initialize(&d->lock); |
return EOK; |
} |
235,7 → 234,7 |
int flags; |
int retval; |
off_t idx; |
size_t size; |
off_t size; |
int disk_id, i; |
/* Get the device handle. */ |
244,7 → 243,7 |
/* Determine which disk device is the client connecting to. */ |
disk_id = -1; |
for (i = 0; i < MAX_DISKS; i++) |
if (disk[i].dev_handle == dh) |
if (dev_handle[i] == dh) |
disk_id = i; |
if (disk_id < 0 || disk[disk_id].present == false) { |
295,14 → 294,14 |
} |
} |
static int ata_bd_rdwr(int disk_id, ipcarg_t method, off_t blk_idx, size_t size, |
static int ata_bd_rdwr(int disk_id, ipcarg_t method, off_t blk_idx, off_t size, |
void *buf) |
{ |
int rc; |
size_t now; |
off_t now; |
while (size > 0) { |
now = size < block_size ? size : block_size; |
now = size < block_size ? size : (off_t) block_size; |
if (now != block_size) |
return EINVAL; |
356,7 → 355,7 |
((disk_id != 0) ? DHR_DRV : 0) | |
(h & 0x0f); |
fibril_mutex_lock(&d->lock); |
futex_down(&dev_futex); |
/* Program a Read Sectors operation. */ |
378,7 → 377,7 |
((uint16_t *) buf)[i] = data; |
} |
fibril_mutex_unlock(&d->lock); |
futex_up(&dev_futex); |
return EOK; |
} |
410,7 → 409,7 |
((disk_id != 0) ? DHR_DRV : 0) | |
(h & 0x0f); |
fibril_mutex_lock(&d->lock); |
futex_down(&dev_futex); |
/* Program a Read Sectors operation. */ |
431,7 → 430,7 |
pio_write_16(&cmd->data_port, ((uint16_t *) buf)[i]); |
} |
fibril_mutex_unlock(&d->lock); |
futex_up(&dev_futex); |
return EOK; |
} |
/branches/dd/uspace/srv/bd/ata_bd/ata_bd.h |
---|
36,7 → 36,6 |
#define __ATA_BD_H__ |
#include <sys/types.h> |
#include <fibril_sync.h> |
enum { |
CTL_READ_START = 0, |
51,32 → 50,22 |
MAX_DISKS = 2 |
}; |
/** ATA Command Register Block. */ |
typedef union { |
/* Read/Write */ |
/* Read */ |
struct { |
uint16_t data_port; |
uint8_t data_port; |
uint8_t error; |
uint8_t sector_count; |
uint8_t sector_number; |
uint8_t cylinder_low; |
uint8_t cylinder_high; |
uint8_t drive_head; |
uint8_t pad_rw0; |
}; |
/* Read Only */ |
struct { |
uint8_t pad_ro0; |
uint8_t error; |
uint8_t pad_ro1[5]; |
uint8_t status; |
}; |
/* Write Only */ |
/* Write */ |
struct { |
uint8_t pad_wo0; |
uint8_t features; |
uint8_t pad_wo1[5]; |
uint8_t pad0[7]; |
uint8_t command; |
}; |
} ata_cmd_t; |
140,9 → 129,6 |
unsigned cylinders; |
unsigned sectors; |
uint64_t blocks; |
fibril_mutex_t lock; |
dev_handle_t dev_handle; |
} disk_t; |
#endif |
/branches/dd/uspace/srv/bd/rd/rd.c |
---|
50,7 → 50,7 |
#include <async.h> |
#include <align.h> |
#include <async.h> |
#include <fibril_sync.h> |
#include <futex.h> |
#include <stdio.h> |
#include <devmap.h> |
#include <ipc/bd.h> |
63,12 → 63,12 |
static size_t rd_size; |
/** |
* This rwlock protects the ramdisk's data. |
* This futex protects the ramdisk's data. |
* If we were to serve multiple requests (read + write or several writes) |
* concurrently (i.e. from two or more threads), each read and write needs to be |
* protected by this rwlock. |
* protected by this futex. |
*/ |
fibril_rwlock_t rd_lock; |
atomic_t rd_futex = FUTEX_INITIALIZER; |
/** Handle one connection to ramdisk. |
* |
139,9 → 139,9 |
retval = ELIMIT; |
break; |
} |
fibril_rwlock_read_lock(&rd_lock); |
futex_down(&rd_futex); |
memcpy(fs_va, rd_addr + offset * block_size, block_size); |
fibril_rwlock_read_unlock(&rd_lock); |
futex_up(&rd_futex); |
retval = EOK; |
break; |
case BD_WRITE_BLOCK: |
161,9 → 161,9 |
retval = ELIMIT; |
break; |
} |
fibril_rwlock_write_lock(&rd_lock); |
futex_up(&rd_futex); |
memcpy(rd_addr + offset * block_size, fs_va, block_size); |
fibril_rwlock_write_unlock(&rd_lock); |
futex_down(&rd_futex); |
retval = EOK; |
break; |
default: |
216,8 → 216,6 |
printf(NAME ": Unable to register device\n"); |
return false; |
} |
fibril_rwlock_initialize(&rd_lock); |
return true; |
} |
/branches/dd/uspace/srv/loader/main.c |
---|
52,8 → 52,6 |
#include <ipc/ipc.h> |
#include <ipc/services.h> |
#include <ipc/loader.h> |
#include <ipc/ns.h> |
#include <macros.h> |
#include <loader/pcb.h> |
#include <errno.h> |
#include <async.h> |
81,7 → 79,7 |
/** Number of preset files */ |
static int filc = 0; |
/** Preset files vector */ |
static fdi_node_t **filv = NULL; |
static char **filv = NULL; |
/** Buffer holding all preset files */ |
static fdi_node_t *fil_buf = NULL; |
439,24 → 437,16 |
int main(int argc, char *argv[]) |
{ |
ipcarg_t phonead; |
task_id_t id; |
int rc; |
connected = false; |
/* Introduce this task to the NS (give it our task ID). */ |
id = task_get_id(); |
rc = async_req_2_0(PHONE_NS, NS_ID_INTRO, LOWER32(id), UPPER32(id)); |
if (rc != EOK) |
return -1; |
/* Set a handler of incomming connections. */ |
async_set_client_connection(ldr_connection); |
/* Register at naming service. */ |
if (ipc_connect_to_me(PHONE_NS, SERVICE_LOAD, 0, 0, &phonead) != 0) |
return -2; |
return -1; |
async_manager(); |
/* Never reached */ |
/branches/dd/uspace/srv/loader/elf_load.c |
---|
74,7 → 74,7 |
static int load_segment(elf_ld_t *elf, elf_segment_header_t *entry); |
/** Read until the buffer is read in its entirety. */ |
static int my_read(int fd, void *buf, size_t len) |
static int my_read(int fd, char *buf, size_t len) |
{ |
int cnt = 0; |
do { |
331,26 → 331,21 |
int flags = 0; |
uintptr_t bias; |
uintptr_t base; |
void *seg_ptr; |
uintptr_t seg_addr; |
size_t mem_sz; |
int rc; |
DPRINTF("Load segment at addr 0x%x, size 0x%x\n", entry->p_vaddr, |
entry->p_memsz); |
bias = elf->bias; |
seg_addr = entry->p_vaddr + bias; |
seg_ptr = (void *) seg_addr; |
DPRINTF("Load segment at addr 0x%x, size 0x%x\n", seg_addr, |
entry->p_memsz); |
if (entry->p_align > 1) { |
if ((entry->p_offset % entry->p_align) != |
(seg_addr % entry->p_align)) { |
(entry->p_vaddr % entry->p_align)) { |
DPRINTF("Align check 1 failed offset%%align=%d, " |
"vaddr%%align=%d\n", |
entry->p_offset % entry->p_align, |
seg_addr % entry->p_align |
entry->p_vaddr % entry->p_align |
); |
return EE_INVALID; |
} |
369,7 → 364,7 |
base = ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE); |
mem_sz = entry->p_memsz + (entry->p_vaddr - base); |
DPRINTF("Map to seg_addr=0x%x-0x%x.\n", seg_addr, |
DPRINTF("Map to p_vaddr=0x%x-0x%x.\n", entry->p_vaddr + bias, |
entry->p_vaddr + bias + ALIGN_UP(entry->p_memsz, PAGE_SIZE)); |
/* |
384,7 → 379,7 |
} |
DPRINTF("as_area_create(0x%lx, 0x%x, %d) -> 0x%lx\n", |
base + bias, mem_sz, flags, (uintptr_t)a); |
entry->p_vaddr+bias, entry->p_memsz, flags, (uintptr_t)a); |
/* |
* Load segment data |
404,7 → 399,7 |
uint8_t *dp; |
left = entry->p_filesz; |
dp = seg_ptr; |
dp = (uint8_t *)(entry->p_vaddr + bias); |
while (left > 0) { |
now = 16384; |
421,7 → 416,7 |
dp += now; |
} |
rc = as_area_change_flags(seg_ptr, flags); |
rc = as_area_change_flags((uint8_t *)entry->p_vaddr + bias, flags); |
if (rc != 0) { |
DPRINTF("Failed to set memory area flags.\n"); |
return EE_MEMORY; |
429,7 → 424,7 |
if (flags & AS_AREA_EXEC) { |
/* Enforce SMC coherence for the segment */ |
if (smc_coherence(seg_ptr, entry->p_filesz)) |
if (smc_coherence(entry->p_vaddr + bias, entry->p_filesz)) |
return EE_MEMORY; |
} |
/branches/dd/uspace/srv/loader/arch/ia32/ia32.s |
---|
46,4 → 46,4 |
# Save a tiny bit of stack space |
pop %ebp |
jmp *%eax |
jmp %eax |
/branches/dd/uspace/srv/fb/serial_console.c |
---|
388,10 → 388,6 |
case FB_GET_CSIZE: |
ipc_answer_2(callid, EOK, scr_width, scr_height); |
continue; |
case FB_GET_COLOR_CAP: |
ipc_answer_1(callid, EOK, color ? FB_CCAP_INDEXED : |
FB_CCAP_STYLE); |
continue; |
case FB_CLEAR: |
serial_clrscr(); |
retval = 0; |
/branches/dd/uspace/srv/fb/fb.c |
---|
56,7 → 56,6 |
#include <async.h> |
#include <fibril.h> |
#include <bool.h> |
#include <stdio.h> |
#include "font-8x16.h" |
#include "fb.h" |
451,8 → 450,7 |
for (row = 0; row < vport->rows; row++) { |
x = vport->x; |
for (col = 0; col < vport->cols; col++) { |
if (((int) row + lines >= 0) && |
((int) row + lines < (int) vport->rows)) { |
if ((row + lines >= 0) && (row + lines < vport->rows)) { |
xbp = &vport->backbuf[BB_POS(vport, col, row + lines)]; |
bbp = &vport->backbuf[BB_POS(vport, col, row)]; |
1068,11 → 1066,10 |
if (IPC_GET_ARG1(*call) == shm_id) { |
void *dest = as_get_mappable_page(IPC_GET_ARG2(*call)); |
shm_size = IPC_GET_ARG2(*call); |
if (ipc_answer_1(callid, EOK, (sysarg_t) dest)) { |
if (!ipc_answer_1(callid, EOK, (sysarg_t) dest)) |
shm = dest; |
else |
shm_id = 0; |
return false; |
} |
shm = dest; |
if (shm[0] != 'P') |
return false; |
1647,9 → 1644,6 |
case FB_GET_CSIZE: |
ipc_answer_2(callid, EOK, vport->cols, vport->rows); |
continue; |
case FB_GET_COLOR_CAP: |
ipc_answer_1(callid, EOK, FB_CCAP_RGB); |
continue; |
case FB_SCROLL: |
scroll = IPC_GET_ARG1(call); |
if ((scroll > (int) vport->rows) || (scroll < (-(int) vport->rows))) { |
/branches/dd/uspace/srv/fb/ega.c |
---|
87,7 → 87,7 |
static void clrscr(void) |
{ |
unsigned i; |
int i; |
for (i = 0; i < scr_width * scr_height; i++) { |
scr_addr[i * 2] = ' '; |
129,8 → 129,7 |
static void scroll(int rows) |
{ |
unsigned i; |
int i; |
if (rows > 0) { |
memmove(scr_addr, ((char *) scr_addr) + rows * scr_width * 2, |
scr_width * scr_height * 2 - rows * scr_width * 2); |
319,9 → 318,6 |
case FB_GET_CSIZE: |
ipc_answer_2(callid, EOK, scr_width, scr_height); |
continue; |
case FB_GET_COLOR_CAP: |
ipc_answer_1(callid, EOK, FB_CCAP_INDEXED); |
continue; |
case FB_CLEAR: |
clrscr(); |
retval = 0; |
349,7 → 345,7 |
break; |
case FB_SCROLL: |
i = IPC_GET_ARG1(call); |
if (i > (int) scr_height || i < -((int) scr_height)) { |
if (i > scr_height || i < -((int) scr_height)) { |
retval = EINVAL; |
break; |
} |
/branches/dd/uspace/srv/fb/ppm.c |
---|
89,7 → 89,7 |
{ |
unsigned int width, height; |
unsigned int maxcolor; |
unsigned int i; |
int i; |
unsigned int color; |
unsigned int coef; |
/branches/dd/uspace/srv/fs/devfs/devfs.c |
---|
65,39 → 65,37 |
ipc_callid_t callid = async_get_call(&call); |
switch (IPC_GET_METHOD(call)) { |
case IPC_M_PHONE_HUNGUP: |
return; |
case VFS_OUT_MOUNTED: |
case VFS_MOUNTED: |
devfs_mounted(callid, &call); |
break; |
case VFS_OUT_MOUNT: |
case VFS_MOUNT: |
devfs_mount(callid, &call); |
break; |
case VFS_OUT_LOOKUP: |
case VFS_LOOKUP: |
devfs_lookup(callid, &call); |
break; |
case VFS_OUT_OPEN_NODE: |
case VFS_OPEN_NODE: |
devfs_open_node(callid, &call); |
break; |
case VFS_OUT_STAT: |
devfs_stat(callid, &call); |
case VFS_DEVICE: |
devfs_device(callid, &call); |
break; |
case VFS_OUT_READ: |
case VFS_READ: |
devfs_read(callid, &call); |
break; |
case VFS_OUT_WRITE: |
case VFS_WRITE: |
devfs_write(callid, &call); |
break; |
case VFS_OUT_TRUNCATE: |
case VFS_TRUNCATE: |
devfs_truncate(callid, &call); |
break; |
case VFS_OUT_CLOSE: |
case VFS_CLOSE: |
devfs_close(callid, &call); |
break; |
case VFS_OUT_SYNC: |
case VFS_SYNC: |
devfs_sync(callid, &call); |
break; |
case VFS_OUT_DESTROY: |
case VFS_DESTROY: |
devfs_destroy(callid, &call); |
break; |
default: |
/branches/dd/uspace/srv/fs/devfs/devfs_ops.c |
---|
41,9 → 41,7 |
#include <malloc.h> |
#include <string.h> |
#include <libfs.h> |
#include <fibril_sync.h> |
#include <adt/hash_table.h> |
#include <sys/stat.h> |
#include "devfs.h" |
#include "devfs_ops.h" |
60,9 → 58,6 |
/** Hash table of opened devices */ |
static hash_table_t devices; |
/** Hash table mutex */ |
static FIBRIL_MUTEX_INITIALIZE(devices_mutex); |
#define DEVICES_KEYS 1 |
#define DEVICES_KEY_HANDLE 0 |
#define DEVICES_BUCKETS 256 |
164,12 → 159,12 |
if (first >= last) { |
/* Root entry */ |
if (!(lflag & L_FILE)) |
if (lflag & L_DIRECTORY) |
ipc_answer_5(rid, EOK, devfs_reg.fs_handle, dev_handle, 0, 0, 0); |
else |
ipc_answer_0(rid, ENOENT); |
} else { |
if (!(lflag & L_DIRECTORY)) { |
if (lflag & L_FILE) { |
size_t len; |
if (last >= first) |
len = last - first + 1; |
200,12 → 195,10 |
[DEVICES_KEY_HANDLE] = (unsigned long) handle |
}; |
fibril_mutex_lock(&devices_mutex); |
link_t *lnk = hash_table_find(&devices, key); |
if (lnk == NULL) { |
int phone = devmap_device_connect(handle, 0); |
if (phone < 0) { |
fibril_mutex_unlock(&devices_mutex); |
free(name); |
ipc_answer_0(rid, ENOENT); |
return; |
213,7 → 206,6 |
device_t *dev = (device_t *) malloc(sizeof(device_t)); |
if (dev == NULL) { |
fibril_mutex_unlock(&devices_mutex); |
free(name); |
ipc_answer_0(rid, ENOMEM); |
return; |
228,7 → 220,6 |
device_t *dev = hash_table_get_instance(lnk, device_t, link); |
dev->refcount++; |
} |
fibril_mutex_unlock(&devices_mutex); |
} |
free(name); |
247,12 → 238,10 |
[DEVICES_KEY_HANDLE] = (unsigned long) handle |
}; |
fibril_mutex_lock(&devices_mutex); |
link_t *lnk = hash_table_find(&devices, key); |
if (lnk == NULL) { |
int phone = devmap_device_connect(handle, 0); |
if (phone < 0) { |
fibril_mutex_unlock(&devices_mutex); |
ipc_answer_0(rid, ENOENT); |
return; |
} |
259,7 → 248,6 |
device_t *dev = (device_t *) malloc(sizeof(device_t)); |
if (dev == NULL) { |
fibril_mutex_unlock(&devices_mutex); |
ipc_answer_0(rid, ENOMEM); |
return; |
} |
273,49 → 261,28 |
device_t *dev = hash_table_get_instance(lnk, device_t, link); |
dev->refcount++; |
} |
fibril_mutex_unlock(&devices_mutex); |
ipc_answer_3(rid, EOK, 0, 1, L_FILE); |
} |
void devfs_stat(ipc_callid_t rid, ipc_call_t *request) |
void devfs_device(ipc_callid_t rid, ipc_call_t *request) |
{ |
dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request); |
fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request); |
ipc_callid_t callid; |
size_t size; |
if (!ipc_data_read_receive(&callid, &size) || |
size != sizeof(struct stat)) { |
ipc_answer_0(callid, EINVAL); |
ipc_answer_0(rid, EINVAL); |
return; |
} |
struct stat stat; |
memset(&stat, 0, sizeof(struct stat)); |
stat.fs_handle = devfs_reg.fs_handle; |
stat.dev_handle = dev_handle; |
stat.index = index; |
stat.lnkcnt = 1; |
stat.is_file = (index != 0); |
stat.size = 0; |
if (index != 0) { |
unsigned long key[] = { |
[DEVICES_KEY_HANDLE] = (unsigned long) index |
}; |
fibril_mutex_lock(&devices_mutex); |
link_t *lnk = hash_table_find(&devices, key); |
if (lnk != NULL) |
stat.devfs_stat.device = (dev_handle_t)index; |
fibril_mutex_unlock(&devices_mutex); |
} |
ipc_data_read_finalize(callid, &stat, sizeof(struct stat)); |
ipc_answer_0(rid, EOK); |
if (lnk == NULL) { |
ipc_answer_0(rid, ENOENT); |
return; |
} |
ipc_answer_1(rid, EOK, (ipcarg_t) index); |
} else |
ipc_answer_0(rid, ENOTSUP); |
} |
void devfs_read(ipc_callid_t rid, ipc_call_t *request) |
328,10 → 295,8 |
[DEVICES_KEY_HANDLE] = (unsigned long) index |
}; |
fibril_mutex_lock(&devices_mutex); |
link_t *lnk = hash_table_find(&devices, key); |
if (lnk == NULL) { |
fibril_mutex_unlock(&devices_mutex); |
ipc_answer_0(rid, ENOENT); |
return; |
} |
340,7 → 305,6 |
ipc_callid_t callid; |
if (!ipc_data_read_receive(&callid, NULL)) { |
fibril_mutex_unlock(&devices_mutex); |
ipc_answer_0(callid, EINVAL); |
ipc_answer_0(rid, EINVAL); |
return; |
354,7 → 318,6 |
/* Forward the IPC_M_DATA_READ request to the driver */ |
ipc_forward_fast(callid, dev->phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME); |
fibril_mutex_unlock(&devices_mutex); |
/* Wait for reply from the driver. */ |
ipcarg_t rc; |
406,10 → 369,8 |
[DEVICES_KEY_HANDLE] = (unsigned long) index |
}; |
fibril_mutex_lock(&devices_mutex); |
link_t *lnk = hash_table_find(&devices, key); |
if (lnk == NULL) { |
fibril_mutex_unlock(&devices_mutex); |
ipc_answer_0(rid, ENOENT); |
return; |
} |
418,7 → 379,6 |
ipc_callid_t callid; |
if (!ipc_data_write_receive(&callid, NULL)) { |
fibril_mutex_unlock(&devices_mutex); |
ipc_answer_0(callid, EINVAL); |
ipc_answer_0(rid, EINVAL); |
return; |
433,8 → 393,6 |
/* Forward the IPC_M_DATA_WRITE request to the driver */ |
ipc_forward_fast(callid, dev->phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME); |
fibril_mutex_unlock(&devices_mutex); |
/* Wait for reply from the driver. */ |
ipcarg_t rc; |
async_wait_for(msg, &rc); |
462,10 → 420,8 |
[DEVICES_KEY_HANDLE] = (unsigned long) index |
}; |
fibril_mutex_lock(&devices_mutex); |
link_t *lnk = hash_table_find(&devices, key); |
if (lnk == NULL) { |
fibril_mutex_unlock(&devices_mutex); |
ipc_answer_0(rid, ENOENT); |
return; |
} |
478,8 → 434,6 |
hash_table_remove(&devices, key, DEVICES_KEYS); |
} |
fibril_mutex_unlock(&devices_mutex); |
ipc_answer_0(rid, EOK); |
} else |
ipc_answer_0(rid, ENOTSUP); |
494,10 → 448,8 |
[DEVICES_KEY_HANDLE] = (unsigned long) index |
}; |
fibril_mutex_lock(&devices_mutex); |
link_t *lnk = hash_table_find(&devices, key); |
if (lnk == NULL) { |
fibril_mutex_unlock(&devices_mutex); |
ipc_answer_0(rid, ENOENT); |
return; |
} |
509,8 → 461,6 |
aid_t msg = async_send_2(dev->phone, IPC_GET_METHOD(*request), |
IPC_GET_ARG1(*request), IPC_GET_ARG2(*request), &answer); |
fibril_mutex_unlock(&devices_mutex); |
/* Wait for reply from the driver */ |
ipcarg_t rc; |
async_wait_for(msg, &rc); |
/branches/dd/uspace/srv/fs/devfs/devfs_ops.h |
---|
42,7 → 42,7 |
extern void devfs_mount(ipc_callid_t, ipc_call_t *); |
extern void devfs_lookup(ipc_callid_t, ipc_call_t *); |
extern void devfs_open_node(ipc_callid_t, ipc_call_t *); |
extern void devfs_stat(ipc_callid_t, ipc_call_t *); |
extern void devfs_device(ipc_callid_t, ipc_call_t *); |
extern void devfs_sync(ipc_callid_t, ipc_call_t *); |
extern void devfs_read(ipc_callid_t, ipc_call_t *); |
extern void devfs_write(ipc_callid_t, ipc_call_t *); |
/branches/dd/uspace/srv/fs/tmpfs/tmpfs.h |
---|
86,10 → 86,10 |
extern void tmpfs_read(ipc_callid_t, ipc_call_t *); |
extern void tmpfs_write(ipc_callid_t, ipc_call_t *); |
extern void tmpfs_truncate(ipc_callid_t, ipc_call_t *); |
extern void tmpfs_stat(ipc_callid_t, ipc_call_t *); |
extern void tmpfs_close(ipc_callid_t, ipc_call_t *); |
extern void tmpfs_destroy(ipc_callid_t, ipc_call_t *); |
extern void tmpfs_open_node(ipc_callid_t, ipc_call_t *); |
extern void tmpfs_device(ipc_callid_t, ipc_call_t *); |
extern void tmpfs_sync(ipc_callid_t, ipc_call_t *); |
extern bool tmpfs_restore(dev_handle_t); |
/branches/dd/uspace/srv/fs/tmpfs/tmpfs.c |
---|
96,39 → 96,37 |
callid = async_get_call(&call); |
switch (IPC_GET_METHOD(call)) { |
case IPC_M_PHONE_HUNGUP: |
return; |
case VFS_OUT_MOUNTED: |
case VFS_MOUNTED: |
tmpfs_mounted(callid, &call); |
break; |
case VFS_OUT_MOUNT: |
case VFS_MOUNT: |
tmpfs_mount(callid, &call); |
break; |
case VFS_OUT_LOOKUP: |
case VFS_LOOKUP: |
tmpfs_lookup(callid, &call); |
break; |
case VFS_OUT_READ: |
case VFS_READ: |
tmpfs_read(callid, &call); |
break; |
case VFS_OUT_WRITE: |
case VFS_WRITE: |
tmpfs_write(callid, &call); |
break; |
case VFS_OUT_TRUNCATE: |
case VFS_TRUNCATE: |
tmpfs_truncate(callid, &call); |
break; |
case VFS_OUT_CLOSE: |
case VFS_CLOSE: |
tmpfs_close(callid, &call); |
break; |
case VFS_OUT_DESTROY: |
case VFS_DESTROY: |
tmpfs_destroy(callid, &call); |
break; |
case VFS_OUT_OPEN_NODE: |
case VFS_OPEN_NODE: |
tmpfs_open_node(callid, &call); |
break; |
case VFS_OUT_STAT: |
tmpfs_stat(callid, &call); |
case VFS_DEVICE: |
tmpfs_device(callid, &call); |
break; |
case VFS_OUT_SYNC: |
case VFS_SYNC: |
tmpfs_sync(callid, &call); |
break; |
default: |
152,7 → 150,7 |
printf(NAME ": Unable to connect to VFS\n"); |
return -1; |
} |
int rc = fs_register(vfs_phone, &tmpfs_reg, &tmpfs_vfs_info, |
tmpfs_connection); |
if (rc != EOK) { |
/branches/dd/uspace/srv/fs/tmpfs/tmpfs_ops.c |
---|
628,9 → 628,9 |
libfs_open_node(&tmpfs_libfs_ops, tmpfs_reg.fs_handle, rid, request); |
} |
void tmpfs_stat(ipc_callid_t rid, ipc_call_t *request) |
void tmpfs_device(ipc_callid_t rid, ipc_call_t *request) |
{ |
libfs_stat(&tmpfs_libfs_ops, tmpfs_reg.fs_handle, rid, request); |
ipc_answer_0(rid, ENOTSUP); |
} |
void tmpfs_sync(ipc_callid_t rid, ipc_call_t *request) |
/branches/dd/uspace/srv/fs/tmpfs/tmpfs_dump.c |
---|
67,8 → 67,8 |
tmpfs_node_t *nodep; |
uint32_t size; |
if (block_seqread(dev, bufpos, buflen, pos, &entry, |
sizeof(entry), TMPFS_BLOCK_SIZE) != EOK) |
if (block_read(dev, bufpos, buflen, pos, &entry, sizeof(entry), |
TMPFS_BLOCK_SIZE) != EOK) |
return false; |
entry.len = uint32_t_le2host(entry.len); |
87,7 → 87,7 |
return false; |
} |
if (block_seqread(dev, bufpos, buflen, pos, fname, |
if (block_read(dev, bufpos, buflen, pos, fname, |
entry.len, TMPFS_BLOCK_SIZE) != EOK) { |
ops->destroy(fn); |
free(fname); |
103,7 → 103,7 |
} |
free(fname); |
if (block_seqread(dev, bufpos, buflen, pos, &size, |
if (block_read(dev, bufpos, buflen, pos, &size, |
sizeof(size), TMPFS_BLOCK_SIZE) != EOK) |
return false; |
115,7 → 115,7 |
return false; |
nodep->size = size; |
if (block_seqread(dev, bufpos, buflen, pos, nodep->data, |
if (block_read(dev, bufpos, buflen, pos, nodep->data, |
size, TMPFS_BLOCK_SIZE) != EOK) |
return false; |
131,7 → 131,7 |
return false; |
} |
if (block_seqread(dev, bufpos, buflen, pos, fname, |
if (block_read(dev, bufpos, buflen, pos, fname, |
entry.len, TMPFS_BLOCK_SIZE) != EOK) { |
ops->destroy(fn); |
free(fname); |
174,7 → 174,7 |
off_t pos = 0; |
char tag[6]; |
if (block_seqread(dev, &bufpos, &buflen, &pos, tag, 5, |
if (block_read(dev, &bufpos, &buflen, &pos, tag, 5, |
TMPFS_BLOCK_SIZE) != EOK) |
goto error; |
/branches/dd/uspace/srv/fs/fat/fat_idx.c |
---|
42,7 → 42,7 |
#include <adt/hash_table.h> |
#include <adt/list.h> |
#include <assert.h> |
#include <fibril_sync.h> |
#include <futex.h> |
/** Each instance of this type describes one interval of freed VFS indices. */ |
typedef struct { |
68,8 → 68,8 |
link_t freed_head; |
} unused_t; |
/** Mutex protecting the list of unused structures. */ |
static FIBRIL_MUTEX_INITIALIZE(unused_lock); |
/** Futex protecting the list of unused structures. */ |
static futex_t unused_futex = FUTEX_INITIALIZER; |
/** List of unused structures. */ |
static LIST_INITIALIZE(unused_head); |
89,7 → 89,7 |
link_t *l; |
if (lock) |
fibril_mutex_lock(&unused_lock); |
futex_down(&unused_futex); |
for (l = unused_head.next; l != &unused_head; l = l->next) { |
u = list_get_instance(l, unused_t, link); |
if (u->dev_handle == dev_handle) |
96,12 → 96,12 |
return u; |
} |
if (lock) |
fibril_mutex_unlock(&unused_lock); |
futex_up(&unused_futex); |
return NULL; |
} |
/** Mutex protecting the up_hash and ui_hash. */ |
static FIBRIL_MUTEX_INITIALIZE(used_lock); |
/** Futex protecting the up_hash and ui_hash. */ |
static futex_t used_futex = FUTEX_INITIALIZER; |
/** |
* Global hash table of all used fat_idx_t structures. |
231,7 → 231,7 |
*/ |
*index = u->next++; |
--u->remaining; |
fibril_mutex_unlock(&unused_lock); |
futex_up(&unused_futex); |
return true; |
} |
} else { |
244,7 → 244,7 |
list_remove(&f->link); |
free(f); |
} |
fibril_mutex_unlock(&unused_lock); |
futex_up(&unused_futex); |
return true; |
} |
/* |
252,7 → 252,7 |
* theoretically still possible (e.g. too many open unlinked nodes or |
* too many zero-sized nodes). |
*/ |
fibril_mutex_unlock(&unused_lock); |
futex_up(&unused_futex); |
return false; |
} |
302,7 → 302,7 |
if (lnk->prev != &u->freed_head) |
try_coalesce_intervals(lnk->prev, lnk, |
lnk); |
fibril_mutex_unlock(&unused_lock); |
futex_up(&unused_futex); |
return; |
} |
if (f->last == index - 1) { |
310,7 → 310,7 |
if (lnk->next != &u->freed_head) |
try_coalesce_intervals(lnk, lnk->next, |
lnk); |
fibril_mutex_unlock(&unused_lock); |
futex_up(&unused_futex); |
return; |
} |
if (index > f->first) { |
321,7 → 321,7 |
n->first = index; |
n->last = index; |
list_insert_before(&n->link, lnk); |
fibril_mutex_unlock(&unused_lock); |
futex_up(&unused_futex); |
return; |
} |
335,7 → 335,7 |
n->last = index; |
list_append(&n->link, &u->freed_head); |
} |
fibril_mutex_unlock(&unused_lock); |
futex_up(&unused_futex); |
} |
static fat_idx_t *fat_idx_create(dev_handle_t dev_handle) |
352,7 → 352,7 |
link_initialize(&fidx->uph_link); |
link_initialize(&fidx->uih_link); |
fibril_mutex_initialize(&fidx->lock); |
futex_initialize(&fidx->lock, 1); |
fidx->dev_handle = dev_handle; |
fidx->pfc = FAT_CLST_RES0; /* no parent yet */ |
fidx->pdi = 0; |
365,10 → 365,10 |
{ |
fat_idx_t *fidx; |
fibril_mutex_lock(&used_lock); |
futex_down(&used_futex); |
fidx = fat_idx_create(dev_handle); |
if (!fidx) { |
fibril_mutex_unlock(&used_lock); |
futex_up(&used_futex); |
return NULL; |
} |
378,8 → 378,8 |
}; |
hash_table_insert(&ui_hash, ikey, &fidx->uih_link); |
fibril_mutex_lock(&fidx->lock); |
fibril_mutex_unlock(&used_lock); |
futex_down(&fidx->lock); |
futex_up(&used_futex); |
return fidx; |
} |
395,7 → 395,7 |
[UPH_PDI_KEY] = pdi, |
}; |
fibril_mutex_lock(&used_lock); |
futex_down(&used_futex); |
l = hash_table_find(&up_hash, pkey); |
if (l) { |
fidx = hash_table_get_instance(l, fat_idx_t, uph_link); |
402,7 → 402,7 |
} else { |
fidx = fat_idx_create(dev_handle); |
if (!fidx) { |
fibril_mutex_unlock(&used_lock); |
futex_up(&used_futex); |
return NULL; |
} |
417,8 → 417,8 |
hash_table_insert(&up_hash, pkey, &fidx->uph_link); |
hash_table_insert(&ui_hash, ikey, &fidx->uih_link); |
} |
fibril_mutex_lock(&fidx->lock); |
fibril_mutex_unlock(&used_lock); |
futex_down(&fidx->lock); |
futex_up(&used_futex); |
return fidx; |
} |
431,9 → 431,9 |
[UPH_PDI_KEY] = idx->pdi, |
}; |
fibril_mutex_lock(&used_lock); |
futex_down(&used_futex); |
hash_table_insert(&up_hash, pkey, &idx->uph_link); |
fibril_mutex_unlock(&used_lock); |
futex_up(&used_futex); |
} |
void fat_idx_hashout(fat_idx_t *idx) |
444,9 → 444,9 |
[UPH_PDI_KEY] = idx->pdi, |
}; |
fibril_mutex_lock(&used_lock); |
futex_down(&used_futex); |
hash_table_remove(&up_hash, pkey, 3); |
fibril_mutex_unlock(&used_lock); |
futex_up(&used_futex); |
} |
fat_idx_t * |
459,13 → 459,13 |
[UIH_INDEX_KEY] = index, |
}; |
fibril_mutex_lock(&used_lock); |
futex_down(&used_futex); |
l = hash_table_find(&ui_hash, ikey); |
if (l) { |
fidx = hash_table_get_instance(l, fat_idx_t, uih_link); |
fibril_mutex_lock(&fidx->lock); |
futex_down(&fidx->lock); |
} |
fibril_mutex_unlock(&used_lock); |
futex_up(&used_futex); |
return fidx; |
} |
483,7 → 483,7 |
assert(idx->pfc == FAT_CLST_RES0); |
fibril_mutex_lock(&used_lock); |
futex_down(&used_futex); |
/* |
* Since we can only free unlinked nodes, the index structure is not |
* present in the position hash (uph). We therefore hash it out from |
490,7 → 490,7 |
* the index hash only. |
*/ |
hash_table_remove(&ui_hash, ikey, 2); |
fibril_mutex_unlock(&used_lock); |
futex_up(&used_futex); |
/* Release the VFS index. */ |
fat_index_free(idx->dev_handle, idx->index); |
/* Deallocate the structure. */ |
524,12 → 524,12 |
if (!u) |
return ENOMEM; |
unused_initialize(u, dev_handle); |
fibril_mutex_lock(&unused_lock); |
futex_down(&unused_futex); |
if (!unused_find(dev_handle, false)) |
list_append(&u->link, &unused_head); |
else |
rc = EEXIST; |
fibril_mutex_unlock(&unused_lock); |
futex_up(&unused_futex); |
return rc; |
} |
540,7 → 540,7 |
u = unused_find(dev_handle, true); |
assert(u); |
list_remove(&u->link); |
fibril_mutex_unlock(&unused_lock); |
futex_up(&unused_futex); |
while (!list_empty(&u->freed_head)) { |
freed_t *f; |
/branches/dd/uspace/srv/fs/fat/fat.h |
---|
35,7 → 35,6 |
#include "fat_fat.h" |
#include <ipc/ipc.h> |
#include <fibril_sync.h> |
#include <libfs.h> |
#include <atomic.h> |
#include <sys/types.h> |
161,7 → 160,7 |
/** Used indices (index) hash table link. */ |
link_t uih_link; |
fibril_mutex_t lock; |
futex_t lock; |
dev_handle_t dev_handle; |
fs_index_t index; |
/** |
182,7 → 181,7 |
/** Back pointer to the FS node. */ |
fs_node_t *bp; |
fibril_mutex_t lock; |
futex_t lock; |
fat_node_type_t type; |
fat_idx_t *idx; |
/** |
207,11 → 206,10 |
extern void fat_read(ipc_callid_t, ipc_call_t *); |
extern void fat_write(ipc_callid_t, ipc_call_t *); |
extern void fat_truncate(ipc_callid_t, ipc_call_t *); |
extern void fat_stat(ipc_callid_t, ipc_call_t *); |
extern void fat_close(ipc_callid_t, ipc_call_t *); |
extern void fat_destroy(ipc_callid_t, ipc_call_t *); |
extern void fat_open_node(ipc_callid_t, ipc_call_t *); |
extern void fat_stat(ipc_callid_t, ipc_call_t *); |
extern void fat_device(ipc_callid_t, ipc_call_t *); |
extern void fat_sync(ipc_callid_t, ipc_call_t *); |
extern fat_idx_t *fat_idx_get_new(dev_handle_t); |
/branches/dd/uspace/srv/fs/fat/fat_fat.c |
---|
45,15 → 45,15 |
#include <byteorder.h> |
#include <align.h> |
#include <assert.h> |
#include <fibril_sync.h> |
#include <futex.h> |
#include <mem.h> |
/** |
* The fat_alloc_lock mutex protects all copies of the File Allocation Table |
* The fat_alloc_lock futex protects all copies of the File Allocation Table |
* during allocation of clusters. The lock does not have to be held durring |
* deallocation of clusters. |
*/ |
static FIBRIL_MUTEX_INITIALIZE(fat_alloc_lock); |
static futex_t fat_alloc_lock = FUTEX_INITIALIZER; |
/** Walk the cluster chain. |
* |
326,7 → 326,7 |
/* |
* Search FAT1 for unused clusters. |
*/ |
fibril_mutex_lock(&fat_alloc_lock); |
futex_down(&fat_alloc_lock); |
for (b = 0, cl = 0; b < sf; b++) { |
blk = block_get(dev_handle, rscnt + b, BLOCK_FLAGS_NONE); |
for (c = 0; c < bps / sizeof(fat_cluster_t); c++, cl++) { |
350,7 → 350,7 |
*mcl = lifo[found - 1]; |
*lcl = lifo[0]; |
free(lifo); |
fibril_mutex_unlock(&fat_alloc_lock); |
futex_up(&fat_alloc_lock); |
return EOK; |
} |
} |
357,7 → 357,7 |
} |
block_put(blk); |
} |
fibril_mutex_unlock(&fat_alloc_lock); |
futex_up(&fat_alloc_lock); |
/* |
* We could not find enough clusters. Now we need to free the clusters |
/branches/dd/uspace/srv/fs/fat/fat.c |
---|
89,39 → 89,37 |
callid = async_get_call(&call); |
switch (IPC_GET_METHOD(call)) { |
case IPC_M_PHONE_HUNGUP: |
return; |
case VFS_OUT_MOUNTED: |
case VFS_MOUNTED: |
fat_mounted(callid, &call); |
break; |
case VFS_OUT_MOUNT: |
case VFS_MOUNT: |
fat_mount(callid, &call); |
break; |
case VFS_OUT_LOOKUP: |
case VFS_LOOKUP: |
fat_lookup(callid, &call); |
break; |
case VFS_OUT_READ: |
case VFS_READ: |
fat_read(callid, &call); |
break; |
case VFS_OUT_WRITE: |
case VFS_WRITE: |
fat_write(callid, &call); |
break; |
case VFS_OUT_TRUNCATE: |
case VFS_TRUNCATE: |
fat_truncate(callid, &call); |
break; |
case VFS_OUT_STAT: |
fat_stat(callid, &call); |
break; |
case VFS_OUT_CLOSE: |
case VFS_CLOSE: |
fat_close(callid, &call); |
break; |
case VFS_OUT_DESTROY: |
case VFS_DESTROY: |
fat_destroy(callid, &call); |
break; |
case VFS_OUT_OPEN_NODE: |
case VFS_OPEN_NODE: |
fat_open_node(callid, &call); |
break; |
case VFS_OUT_SYNC: |
case VFS_DEVICE: |
fat_device(callid, &call); |
break; |
case VFS_SYNC: |
fat_sync(callid, &call); |
break; |
default: |
/branches/dd/uspace/srv/fs/fat/fat_ops.c |
---|
51,7 → 51,7 |
#include <adt/hash_table.h> |
#include <adt/list.h> |
#include <assert.h> |
#include <fibril_sync.h> |
#include <futex.h> |
#include <sys/mman.h> |
#include <align.h> |
58,8 → 58,8 |
#define FAT_NODE(node) ((node) ? (fat_node_t *) (node)->data : NULL) |
#define FS_NODE(node) ((node) ? (node)->bp : NULL) |
/** Mutex protecting the list of cached free FAT nodes. */ |
static FIBRIL_MUTEX_INITIALIZE(ffn_mutex); |
/** Futex protecting the list of cached free FAT nodes. */ |
static futex_t ffn_futex = FUTEX_INITIALIZER; |
/** List of cached free FAT nodes. */ |
static LIST_INITIALIZE(ffn_head); |
66,7 → 66,7 |
static void fat_node_initialize(fat_node_t *node) |
{ |
fibril_mutex_initialize(&node->lock); |
futex_initialize(&node->lock, 1); |
node->bp = NULL; |
node->idx = NULL; |
node->type = 0; |
115,30 → 115,30 |
fs_node_t *fn; |
fat_node_t *nodep; |
fibril_mutex_lock(&ffn_mutex); |
futex_down(&ffn_futex); |
if (!list_empty(&ffn_head)) { |
/* Try to use a cached free node structure. */ |
fat_idx_t *idxp_tmp; |
nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link); |
if (!fibril_mutex_trylock(&nodep->lock)) |
if (futex_trydown(&nodep->lock) == ESYNCH_WOULD_BLOCK) |
goto skip_cache; |
idxp_tmp = nodep->idx; |
if (!fibril_mutex_trylock(&idxp_tmp->lock)) { |
fibril_mutex_unlock(&nodep->lock); |
if (futex_trydown(&idxp_tmp->lock) == ESYNCH_WOULD_BLOCK) { |
futex_up(&nodep->lock); |
goto skip_cache; |
} |
list_remove(&nodep->ffn_link); |
fibril_mutex_unlock(&ffn_mutex); |
futex_up(&ffn_futex); |
if (nodep->dirty) |
fat_node_sync(nodep); |
idxp_tmp->nodep = NULL; |
fibril_mutex_unlock(&nodep->lock); |
fibril_mutex_unlock(&idxp_tmp->lock); |
futex_up(&nodep->lock); |
futex_up(&idxp_tmp->lock); |
fn = FS_NODE(nodep); |
} else { |
skip_cache: |
/* Try to allocate a new node structure. */ |
fibril_mutex_unlock(&ffn_mutex); |
futex_up(&ffn_futex); |
fn = (fs_node_t *)malloc(sizeof(fs_node_t)); |
if (!fn) |
return NULL; |
175,10 → 175,10 |
* We are lucky. |
* The node is already instantiated in memory. |
*/ |
fibril_mutex_lock(&idxp->nodep->lock); |
futex_down(&idxp->nodep->lock); |
if (!idxp->nodep->refcnt++) |
list_remove(&idxp->nodep->ffn_link); |
fibril_mutex_unlock(&idxp->nodep->lock); |
futex_up(&idxp->nodep->lock); |
return idxp->nodep; |
} |
268,7 → 268,7 |
return NULL; |
/* idxp->lock held */ |
nodep = fat_node_get_core(idxp); |
fibril_mutex_unlock(&idxp->lock); |
futex_up(&idxp->lock); |
return FS_NODE(nodep); |
} |
277,12 → 277,12 |
fat_node_t *nodep = FAT_NODE(fn); |
bool destroy = false; |
fibril_mutex_lock(&nodep->lock); |
futex_down(&nodep->lock); |
if (!--nodep->refcnt) { |
if (nodep->idx) { |
fibril_mutex_lock(&ffn_mutex); |
futex_down(&ffn_futex); |
list_append(&nodep->ffn_link, &ffn_head); |
fibril_mutex_unlock(&ffn_mutex); |
futex_up(&ffn_futex); |
} else { |
/* |
* The node does not have any index structure associated |
293,7 → 293,7 |
destroy = true; |
} |
} |
fibril_mutex_unlock(&nodep->lock); |
futex_up(&nodep->lock); |
if (destroy) { |
free(nodep->bp); |
free(nodep); |
360,7 → 360,7 |
nodep->idx = idxp; |
idxp->nodep = nodep; |
fibril_mutex_unlock(&idxp->lock); |
futex_up(&idxp->lock); |
return FS_NODE(nodep); |
} |
409,16 → 409,16 |
fat_cluster_t mcl, lcl; |
int rc; |
fibril_mutex_lock(&childp->lock); |
futex_down(&childp->lock); |
if (childp->lnkcnt == 1) { |
/* |
* On FAT, we don't support multiple hard links. |
*/ |
fibril_mutex_unlock(&childp->lock); |
futex_up(&childp->lock); |
return EMLINK; |
} |
assert(childp->lnkcnt == 0); |
fibril_mutex_unlock(&childp->lock); |
futex_up(&childp->lock); |
if (!fat_dentry_name_verify(name)) { |
/* |
432,7 → 432,7 |
* a new one. |
*/ |
fibril_mutex_lock(&parentp->idx->lock); |
futex_down(&parentp->idx->lock); |
bs = block_bb_get(parentp->idx->dev_handle); |
bps = uint16_t_le2host(bs->bps); |
dps = bps / sizeof(fat_dentry_t); |
463,12 → 463,12 |
*/ |
if (parentp->idx->pfc == FAT_CLST_ROOT) { |
/* Can't grow the root directory. */ |
fibril_mutex_unlock(&parentp->idx->lock); |
futex_up(&parentp->idx->lock); |
return ENOSPC; |
} |
rc = fat_alloc_clusters(bs, parentp->idx->dev_handle, 1, &mcl, &lcl); |
if (rc != EOK) { |
fibril_mutex_unlock(&parentp->idx->lock); |
futex_up(&parentp->idx->lock); |
return rc; |
} |
fat_append_clusters(bs, parentp, mcl); |
491,9 → 491,9 |
fat_dentry_name_set(d, name); |
b->dirty = true; /* need to sync block */ |
block_put(b); |
fibril_mutex_unlock(&parentp->idx->lock); |
futex_up(&parentp->idx->lock); |
fibril_mutex_lock(&childp->idx->lock); |
futex_down(&childp->idx->lock); |
/* |
* If possible, create the Sub-directory Identifier Entry and the |
529,12 → 529,12 |
childp->idx->pfc = parentp->firstc; |
childp->idx->pdi = i * dps + j; |
fibril_mutex_unlock(&childp->idx->lock); |
futex_up(&childp->idx->lock); |
fibril_mutex_lock(&childp->lock); |
futex_down(&childp->lock); |
childp->lnkcnt = 1; |
childp->dirty = true; /* need to sync node */ |
fibril_mutex_unlock(&childp->lock); |
futex_up(&childp->lock); |
/* |
* Hash in the index structure into the position hash. |
559,10 → 559,10 |
if (fat_has_children(cfn)) |
return ENOTEMPTY; |
fibril_mutex_lock(&parentp->lock); |
fibril_mutex_lock(&childp->lock); |
futex_down(&parentp->lock); |
futex_down(&childp->lock); |
assert(childp->lnkcnt == 1); |
fibril_mutex_lock(&childp->idx->lock); |
futex_down(&childp->idx->lock); |
bs = block_bb_get(childp->idx->dev_handle); |
bps = uint16_t_le2host(bs->bps); |
581,11 → 581,11 |
/* clear position information */ |
childp->idx->pfc = FAT_CLST_RES0; |
childp->idx->pdi = 0; |
fibril_mutex_unlock(&childp->idx->lock); |
futex_up(&childp->idx->lock); |
childp->lnkcnt = 0; |
childp->dirty = true; |
fibril_mutex_unlock(&childp->lock); |
fibril_mutex_unlock(&parentp->lock); |
futex_up(&childp->lock); |
futex_up(&parentp->lock); |
return EOK; |
} |
602,7 → 602,7 |
fat_dentry_t *d; |
block_t *b; |
fibril_mutex_lock(&parentp->idx->lock); |
futex_down(&parentp->idx->lock); |
bs = block_bb_get(parentp->idx->dev_handle); |
bps = uint16_t_le2host(bs->bps); |
dps = bps / sizeof(fat_dentry_t); |
617,7 → 617,7 |
continue; |
case FAT_DENTRY_LAST: |
block_put(b); |
fibril_mutex_unlock(&parentp->idx->lock); |
futex_up(&parentp->idx->lock); |
return NULL; |
default: |
case FAT_DENTRY_VALID: |
636,7 → 636,7 |
fat_idx_t *idx = fat_idx_get_by_pos( |
parentp->idx->dev_handle, parentp->firstc, |
i * dps + j); |
fibril_mutex_unlock(&parentp->idx->lock); |
futex_up(&parentp->idx->lock); |
if (!idx) { |
/* |
* Can happen if memory is low or if we |
646,7 → 646,7 |
return NULL; |
} |
nodep = fat_node_get_core(idx); |
fibril_mutex_unlock(&idx->lock); |
futex_up(&idx->lock); |
block_put(b); |
return FS_NODE(nodep); |
} |
654,7 → 654,7 |
block_put(b); |
} |
fibril_mutex_unlock(&parentp->idx->lock); |
futex_up(&parentp->idx->lock); |
return NULL; |
} |
686,7 → 686,7 |
if (nodep->type != FAT_DIRECTORY) |
return false; |
fibril_mutex_lock(&nodep->idx->lock); |
futex_down(&nodep->idx->lock); |
bs = block_bb_get(nodep->idx->dev_handle); |
bps = uint16_t_le2host(bs->bps); |
dps = bps / sizeof(fat_dentry_t); |
705,22 → 705,22 |
continue; |
case FAT_DENTRY_LAST: |
block_put(b); |
fibril_mutex_unlock(&nodep->idx->lock); |
futex_up(&nodep->idx->lock); |
return false; |
default: |
case FAT_DENTRY_VALID: |
block_put(b); |
fibril_mutex_unlock(&nodep->idx->lock); |
futex_up(&nodep->idx->lock); |
return true; |
} |
block_put(b); |
fibril_mutex_unlock(&nodep->idx->lock); |
futex_up(&nodep->idx->lock); |
return true; |
} |
block_put(b); |
} |
fibril_mutex_unlock(&nodep->idx->lock); |
futex_up(&nodep->idx->lock); |
return false; |
} |
770,7 → 770,6 |
void fat_mounted(ipc_callid_t rid, ipc_call_t *request) |
{ |
dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request); |
enum cache_mode cmode; |
fat_bs_t *bs; |
uint16_t bps; |
uint16_t rde; |
798,12 → 797,6 |
} |
opts[size] = '\0'; |
/* Check for option enabling write through. */ |
if (str_cmp(opts, "wtcache") == 0) |
cmode = CACHE_MODE_WT; |
else |
cmode = CACHE_MODE_WB; |
/* initialize libblock */ |
rc = block_init(dev_handle, BS_SIZE); |
if (rc != EOK) { |
833,7 → 826,7 |
} |
/* Initialize the block cache */ |
rc = block_cache_init(dev_handle, bps, 0 /* XXX */, cmode); |
rc = block_cache_init(dev_handle, bps, 0 /* XXX */); |
if (rc != EOK) { |
block_fini(dev_handle); |
ipc_answer_0(rid, rc); |
888,7 → 881,7 |
rootp->bp = rfn; |
rfn->data = rootp; |
fibril_mutex_unlock(&ridxp->lock); |
futex_up(&ridxp->lock); |
ipc_answer_3(rid, EOK, ridxp->index, rootp->size, rootp->lnkcnt); |
} |
1202,9 → 1195,9 |
libfs_open_node(&fat_libfs_ops, fat_reg.fs_handle, rid, request); |
} |
void fat_stat(ipc_callid_t rid, ipc_call_t *request) |
void fat_device(ipc_callid_t rid, ipc_call_t *request) |
{ |
libfs_stat(&fat_libfs_ops, fat_reg.fs_handle, rid, request); |
ipc_answer_0(rid, ENOTSUP); |
} |
void fat_sync(ipc_callid_t rid, ipc_call_t *request) |
/branches/dd/uspace/srv/devmap/devmap.c |
---|
46,8 → 46,7 |
#include <string.h> |
#include <ipc/devmap.h> |
#define NAME "devmap" |
#define NULL_DEVICES 256 |
#define NAME "devmap" |
/** Representation of device driver. |
* |
84,8 → 83,16 |
devmap_driver_t *driver; |
} devmap_device_t; |
/** Pending lookup structure. */ |
typedef struct { |
link_t link; |
char *name; /**< Device name */ |
ipc_callid_t callid; /**< Call ID waiting for the lookup */ |
} pending_req_t; |
LIST_INITIALIZE(devices_list); |
LIST_INITIALIZE(drivers_list); |
LIST_INITIALIZE(pending_req); |
/* Locking order: |
* drivers_list_mutex |
95,13 → 102,10 |
**/ |
static FIBRIL_MUTEX_INITIALIZE(devices_list_mutex); |
static FIBRIL_CONDVAR_INITIALIZE(devices_list_cv); |
static FIBRIL_MUTEX_INITIALIZE(drivers_list_mutex); |
static FIBRIL_MUTEX_INITIALIZE(create_handle_mutex); |
static FIBRIL_MUTEX_INITIALIZE(null_devices_mutex); |
static dev_handle_t last_handle = 0; |
static devmap_device_t *null_devices[NULL_DEVICES]; |
static dev_handle_t devmap_create_handle(void) |
{ |
170,8 → 174,10 |
} |
/** |
* |
* Unregister device and free it. It's assumed that driver's device list is |
* already locked. |
* |
*/ |
static int devmap_device_unregister_core(devmap_device_t *device) |
{ |
185,8 → 191,10 |
} |
/** |
* |
* Read info about new driver and add it into linked list of registered |
* drivers. |
* |
*/ |
static void devmap_driver_register(devmap_driver_t **odriver) |
{ |
336,6 → 344,31 |
return EOK; |
} |
/** Process pending lookup requests */ |
static void process_pending_lookup(void) |
{ |
link_t *cur; |
loop: |
for (cur = pending_req.next; cur != &pending_req; cur = cur->next) { |
pending_req_t *pr = list_get_instance(cur, pending_req_t, link); |
const devmap_device_t *dev = devmap_device_find_name(pr->name); |
if (!dev) |
continue; |
ipc_answer_1(pr->callid, EOK, dev->handle); |
free(pr->name); |
list_remove(cur); |
free(pr); |
goto loop; |
} |
} |
/** Register instance of device |
* |
*/ |
412,7 → 445,6 |
list_append(&device->driver_devices, &device->driver->devices); |
fibril_mutex_unlock(&device->driver->devices_mutex); |
fibril_condvar_broadcast(&devices_list_cv); |
fibril_mutex_unlock(&devices_list_mutex); |
ipc_answer_1(iid, EOK, device->handle); |
498,14 → 530,10 |
} |
name[size] = '\0'; |
fibril_mutex_lock(&devices_list_mutex); |
const devmap_device_t *dev; |
recheck: |
/* |
* Find device name in the list of known devices. |
* Find device name in linked list of known devices. |
*/ |
dev = devmap_device_find_name(name); |
const devmap_device_t *dev = devmap_device_find_name(name); |
/* |
* Device was not found. |
512,18 → 540,24 |
*/ |
if (dev == NULL) { |
if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) { |
/* Blocking lookup */ |
fibril_condvar_wait(&devices_list_cv, |
&devices_list_mutex); |
goto recheck; |
/* Blocking lookup, add to pending list */ |
pending_req_t *pr = (pending_req_t *) malloc(sizeof(pending_req_t)); |
if (!pr) { |
ipc_answer_0(iid, ENOMEM); |
free(name); |
return; |
} |
pr->name = name; |
pr->callid = iid; |
list_append(&pr->link, &pending_req); |
return; |
} |
ipc_answer_0(iid, ENOENT); |
free(name); |
fibril_mutex_unlock(&devices_list_mutex); |
return; |
} |
fibril_mutex_unlock(&devices_list_mutex); |
ipc_answer_1(iid, EOK, dev->handle); |
free(name); |
621,43 → 655,21 |
ipc_answer_1(iid, EOK, pos); |
} |
static void devmap_null_create(ipc_callid_t iid, ipc_call_t *icall) |
/** Initialize device mapper. |
* |
* |
*/ |
static bool devmap_init() |
{ |
fibril_mutex_lock(&null_devices_mutex); |
unsigned int i; |
bool fnd = false; |
for (i = 0; i < NULL_DEVICES; i++) { |
if (null_devices[i] == NULL) { |
fnd = true; |
break; |
} |
} |
if (!fnd) { |
fibril_mutex_unlock(&null_devices_mutex); |
ipc_answer_0(iid, ENOMEM); |
return; |
} |
/* Create NULL device entry */ |
devmap_device_t *device = (devmap_device_t *) malloc(sizeof(devmap_device_t)); |
if (device == NULL) { |
fibril_mutex_unlock(&null_devices_mutex); |
ipc_answer_0(iid, ENOMEM); |
return; |
} |
if (device == NULL) |
return false; |
char null[DEVMAP_NAME_MAXLEN]; |
snprintf(null, DEVMAP_NAME_MAXLEN, "null%u", i); |
device->name = str_dup(null); |
device->name = str_dup("null"); |
if (device->name == NULL) { |
fibril_mutex_unlock(&null_devices_mutex); |
free(device); |
ipc_answer_0(iid, ENOMEM); |
return; |
return false; |
} |
list_initialize(&(device->devices)); |
669,50 → 681,11 |
device->handle = devmap_create_handle(); |
device->driver = NULL; |
/* Insert device into list of all devices |
and into null devices array */ |
/* Insert device into list of all devices */ |
list_append(&device->devices, &devices_list); |
null_devices[i] = device; |
fibril_mutex_unlock(&devices_list_mutex); |
fibril_mutex_unlock(&null_devices_mutex); |
ipc_answer_1(iid, EOK, (ipcarg_t) i); |
} |
static void devmap_null_destroy(ipc_callid_t iid, ipc_call_t *icall) |
{ |
fibril_mutex_lock(&null_devices_mutex); |
ipcarg_t i = IPC_GET_ARG1(*icall); |
if (null_devices[i] == NULL) { |
ipc_answer_0(iid, ENOENT); |
return; |
} |
devmap_device_unregister_core(null_devices[i]); |
null_devices[i] = NULL; |
fibril_mutex_unlock(&null_devices_mutex); |
ipc_answer_0(iid, EOK); |
} |
/** Initialize device mapper. |
* |
* |
*/ |
static bool devmap_init(void) |
{ |
fibril_mutex_lock(&null_devices_mutex); |
unsigned int i; |
for (i = 0; i < NULL_DEVICES; i++) |
null_devices[i] = NULL; |
fibril_mutex_unlock(&null_devices_mutex); |
return true; |
} |
765,7 → 738,7 |
} |
} |
if (driver != NULL) { |
if (NULL != driver) { |
/* |
* Unregister the device driver and all its devices. |
*/ |
797,12 → 770,6 |
case DEVMAP_DEVICE_GET_NAME: |
devmap_get_name(callid, &call); |
break; |
case DEVMAP_DEVICE_NULL_CREATE: |
devmap_null_create(callid, &call); |
break; |
case DEVMAP_DEVICE_NULL_DESTROY: |
devmap_null_destroy(callid, &call); |
break; |
case DEVMAP_DEVICE_GET_COUNT: |
devmap_get_count(callid, &call); |
break; |
851,7 → 818,9 |
return -1; |
} |
/* Set a handler of incomming connections */ |
/* Set a handler of incomming connections and |
pending operations */ |
async_set_pending(process_pending_lookup); |
async_set_client_connection(devmap_connection); |
/* Register device mapper at naming service */ |
/branches/dd/uspace/srv/vfs/vfs.c |
---|
43,6 → 43,7 |
#include <bool.h> |
#include <string.h> |
#include <as.h> |
#include <adt/list.h> |
#include <atomic.h> |
#include "vfs.h" |
79,52 → 80,56 |
case IPC_M_PHONE_HUNGUP: |
keep_on_going = false; |
break; |
case VFS_IN_REGISTER: |
case VFS_REGISTER: |
vfs_register(callid, &call); |
keep_on_going = false; |
/* |
* Keep the connection open so that a file system can |
* later ask us to connect it to another file system. |
* This is necessary to support non-root mounts. |
*/ |
break; |
case VFS_IN_MOUNT: |
case VFS_MOUNT: |
vfs_mount(callid, &call); |
break; |
case VFS_IN_OPEN: |
case VFS_OPEN: |
vfs_open(callid, &call); |
break; |
case VFS_IN_OPEN_NODE: |
case VFS_OPEN_NODE: |
vfs_open_node(callid, &call); |
break; |
case VFS_IN_CLOSE: |
case VFS_CLOSE: |
vfs_close(callid, &call); |
break; |
case VFS_IN_READ: |
case VFS_READ: |
vfs_read(callid, &call); |
break; |
case VFS_IN_WRITE: |
case VFS_WRITE: |
vfs_write(callid, &call); |
break; |
case VFS_IN_SEEK: |
case VFS_SEEK: |
vfs_seek(callid, &call); |
break; |
case VFS_IN_TRUNCATE: |
case VFS_TRUNCATE: |
vfs_truncate(callid, &call); |
break; |
case VFS_IN_FSTAT: |
vfs_fstat(callid, &call); |
break; |
case VFS_IN_STAT: |
vfs_stat(callid, &call); |
break; |
case VFS_IN_MKDIR: |
case VFS_MKDIR: |
vfs_mkdir(callid, &call); |
break; |
case VFS_IN_UNLINK: |
case VFS_UNLINK: |
vfs_unlink(callid, &call); |
break; |
case VFS_IN_RENAME: |
case VFS_RENAME: |
vfs_rename(callid, &call); |
break; |
case VFS_IN_SYNC: |
case VFS_DEVICE: |
vfs_device(callid, &call); |
break; |
case VFS_SYNC: |
vfs_sync(callid, &call); |
break; |
case VFS_NODE: |
vfs_node(callid, &call); |
break; |
default: |
ipc_answer_0(callid, ENOTSUP); |
break; |
139,6 → 144,11 |
printf(NAME ": HelenOS VFS server\n"); |
/* |
* Initialize the list of registered file systems. |
*/ |
list_initialize(&fs_head); |
/* |
* Initialize VFS node hash table. |
*/ |
if (!vfs_nodes_init()) { |
149,6 → 159,7 |
/* |
* Allocate and initialize the Path Lookup Buffer. |
*/ |
list_initialize(&plb_head); |
plb = as_get_mappable_page(PLB_SIZE); |
if (!plb) { |
printf(NAME ": Cannot allocate a mappable piece of address space\n"); |
163,10 → 174,11 |
memset(plb, 0, PLB_SIZE); |
/* |
* Set a connection handling function/fibril. |
* Set a connectio handling function/fibril. |
*/ |
async_set_pending(vfs_process_pending_mount); |
async_set_client_connection(vfs_connection); |
/* |
* Register at the naming service. |
*/ |
/branches/dd/uspace/srv/vfs/vfs_ops.c |
---|
43,6 → 43,7 |
#include <stdlib.h> |
#include <string.h> |
#include <bool.h> |
#include <futex.h> |
#include <fibril_sync.h> |
#include <adt/list.h> |
#include <unistd.h> |
54,6 → 55,20 |
/* Forward declarations of static functions. */ |
static int vfs_truncate_internal(fs_handle_t, dev_handle_t, fs_index_t, size_t); |
/** Pending mount structure. */ |
typedef struct { |
link_t link; |
char *fs_name; /**< File system name */ |
char *mp; /**< Mount point */ |
char *opts; /**< Mount options. */ |
ipc_callid_t callid; /**< Call ID waiting for the mount */ |
ipc_callid_t rid; /**< Request ID */ |
dev_handle_t dev_handle; /**< Device handle */ |
} pending_req_t; |
FIBRIL_MUTEX_INITIALIZE(pending_lock); |
LIST_INITIALIZE(pending_req); |
/** |
* This rwlock prevents the race between a triplet-to-VFS-node resolution and a |
* concurrent VFS operation which modifies the file system namespace. |
108,7 → 123,7 |
/* |
* Now we hold a reference to mp_node. |
* It will be dropped upon the corresponding VFS_IN_UNMOUNT. |
* It will be dropped upon the corresponding VFS_UNMOUNT. |
* This prevents the mount point from being deleted. |
*/ |
} else { |
121,20 → 136,20 |
/* Tell the mountee that it is being mounted. */ |
phone = vfs_grab_phone(fs_handle); |
msg = async_send_1(phone, VFS_OUT_MOUNTED, |
msg = async_send_1(phone, VFS_MOUNTED, |
(ipcarg_t) dev_handle, &answer); |
/* send the mount options */ |
rc = ipc_data_write_start(phone, (void *)opts, |
str_size(opts)); |
if (rc != EOK) { |
vfs_release_phone(phone); |
async_wait_for(msg, NULL); |
vfs_release_phone(phone); |
fibril_rwlock_write_unlock(&namespace_rwlock); |
ipc_answer_0(rid, rc); |
return; |
} |
vfs_release_phone(phone); |
async_wait_for(msg, &rc); |
vfs_release_phone(phone); |
if (rc != EOK) { |
fibril_rwlock_write_unlock(&namespace_rwlock); |
181,9 → 196,10 |
int mountee_phone = vfs_grab_phone(fs_handle); |
assert(mountee_phone >= 0); |
vfs_release_phone(mountee_phone); |
phone = vfs_grab_phone(mp_res.triplet.fs_handle); |
msg = async_send_4(phone, VFS_OUT_MOUNT, |
msg = async_send_4(phone, VFS_MOUNT, |
(ipcarg_t) mp_res.triplet.dev_handle, |
(ipcarg_t) mp_res.triplet.index, |
(ipcarg_t) fs_handle, |
192,9 → 208,8 |
/* send connection */ |
rc = async_req_1_0(phone, IPC_M_CONNECTION_CLONE, mountee_phone); |
if (rc != EOK) { |
vfs_release_phone(phone); |
async_wait_for(msg, NULL); |
vfs_release_phone(mountee_phone); |
vfs_release_phone(phone); |
/* Mount failed, drop reference to mp_node. */ |
if (mp_node) |
vfs_node_put(mp_node); |
202,14 → 217,12 |
fibril_rwlock_write_unlock(&namespace_rwlock); |
return; |
} |
vfs_release_phone(mountee_phone); |
/* send the mount options */ |
rc = ipc_data_write_start(phone, (void *)opts, str_size(opts)); |
if (rc != EOK) { |
vfs_release_phone(phone); |
async_wait_for(msg, NULL); |
vfs_release_phone(phone); |
/* Mount failed, drop reference to mp_node. */ |
if (mp_node) |
vfs_node_put(mp_node); |
217,8 → 230,8 |
ipc_answer_0(rid, rc); |
return; |
} |
vfs_release_phone(phone); |
async_wait_for(msg, &rc); |
vfs_release_phone(phone); |
if (rc == EOK) { |
rindex = (fs_index_t) IPC_GET_ARG1(answer); |
245,6 → 258,39 |
fibril_rwlock_write_unlock(&namespace_rwlock); |
} |
/** Process pending mount requests */ |
void vfs_process_pending_mount(void) |
{ |
link_t *cur; |
loop: |
fibril_mutex_lock(&pending_lock); |
for (cur = pending_req.next; cur != &pending_req; cur = cur->next) { |
pending_req_t *pr = list_get_instance(cur, pending_req_t, link); |
fs_handle_t fs_handle = fs_name_to_handle(pr->fs_name, true); |
if (!fs_handle) |
continue; |
/* Acknowledge that we know fs_name. */ |
ipc_answer_0(pr->callid, EOK); |
/* Do the mount */ |
vfs_mount_internal(pr->rid, pr->dev_handle, fs_handle, pr->mp, |
pr->opts); |
free(pr->fs_name); |
free(pr->mp); |
free(pr->opts); |
list_remove(cur); |
free(pr); |
fibril_mutex_unlock(&pending_lock); |
fibril_yield(); |
goto loop; |
} |
fibril_mutex_unlock(&pending_lock); |
} |
void vfs_mount(ipc_callid_t rid, ipc_call_t *request) |
{ |
/* |
398,17 → 444,35 |
* Check if we know a file system with the same name as is in fs_name. |
* This will also give us its file system handle. |
*/ |
fibril_mutex_lock(&fs_head_lock); |
fs_handle_t fs_handle; |
recheck: |
fs_handle = fs_name_to_handle(fs_name, false); |
fs_handle_t fs_handle = fs_name_to_handle(fs_name, true); |
if (!fs_handle) { |
if (flags & IPC_FLAG_BLOCKING) { |
fibril_condvar_wait(&fs_head_cv, &fs_head_lock); |
goto recheck; |
pending_req_t *pr; |
/* Blocking mount, add to pending list */ |
pr = (pending_req_t *) malloc(sizeof(pending_req_t)); |
if (!pr) { |
ipc_answer_0(callid, ENOMEM); |
ipc_answer_0(rid, ENOMEM); |
free(mp); |
free(fs_name); |
free(opts); |
return; |
} |
pr->fs_name = fs_name; |
pr->mp = mp; |
pr->opts = opts; |
pr->callid = callid; |
pr->rid = rid; |
pr->dev_handle = dev_handle; |
link_initialize(&pr->link); |
fibril_mutex_lock(&pending_lock); |
list_append(&pr->link, &pending_req); |
fibril_mutex_unlock(&pending_lock); |
return; |
} |
fibril_mutex_unlock(&fs_head_lock); |
ipc_answer_0(callid, ENOENT); |
ipc_answer_0(rid, ENOENT); |
free(mp); |
416,7 → 480,6 |
free(opts); |
return; |
} |
fibril_mutex_unlock(&fs_head_lock); |
/* Acknowledge that we know fs_name. */ |
ipc_answer_0(callid, EOK); |
437,8 → 500,8 |
/* |
* The POSIX interface is open(path, oflag, mode). |
* We can receive oflags and mode along with the VFS_IN_OPEN call; |
* the path will need to arrive in another call. |
* We can receive oflags and mode along with the VFS_OPEN call; the path |
* will need to arrive in another call. |
* |
* We also receive one private, non-POSIX set of flags called lflag |
* used to pass information to vfs_lookup_internal(). |
555,7 → 618,7 |
* file is being opened and that a file structure is pointing to it. |
* It is necessary so that the file will not disappear when |
* vfs_node_put() is called. The reference will be dropped by the |
* respective VFS_IN_CLOSE. |
* respective VFS_CLOSE. |
*/ |
vfs_node_addref(node); |
vfs_node_put(node); |
632,7 → 695,7 |
* file is being opened and that a file structure is pointing to it. |
* It is necessary so that the file will not disappear when |
* vfs_node_put() is called. The reference will be dropped by the |
* respective VFS_IN_CLOSE. |
* respective VFS_CLOSE. |
*/ |
vfs_node_addref(node); |
vfs_node_put(node); |
641,6 → 704,56 |
ipc_answer_1(rid, EOK, fd); |
} |
void vfs_node(ipc_callid_t rid, ipc_call_t *request) |
{ |
int fd = IPC_GET_ARG1(*request); |
/* Lookup the file structure corresponding to the file descriptor. */ |
vfs_file_t *file = vfs_file_get(fd); |
if (!file) { |
ipc_answer_0(rid, ENOENT); |
return; |
} |
ipc_answer_3(rid, EOK, file->node->fs_handle, file->node->dev_handle, |
file->node->index); |
} |
void vfs_device(ipc_callid_t rid, ipc_call_t *request) |
{ |
int fd = IPC_GET_ARG1(*request); |
/* Lookup the file structure corresponding to the file descriptor. */ |
vfs_file_t *file = vfs_file_get(fd); |
if (!file) { |
ipc_answer_0(rid, ENOENT); |
return; |
} |
/* |
* Lock the open file structure so that no other thread can manipulate |
* the same open file at a time. |
*/ |
fibril_mutex_lock(&file->lock); |
int fs_phone = vfs_grab_phone(file->node->fs_handle); |
/* Make a VFS_DEVICE request at the destination FS server. */ |
aid_t msg; |
ipc_call_t answer; |
msg = async_send_2(fs_phone, IPC_GET_METHOD(*request), |
file->node->dev_handle, file->node->index, &answer); |
vfs_release_phone(fs_phone); |
/* Wait for reply from the FS server. */ |
ipcarg_t rc; |
async_wait_for(msg, &rc); |
fibril_mutex_unlock(&file->lock); |
ipc_answer_1(rid, EOK, IPC_GET_ARG1(answer)); |
} |
void vfs_sync(ipc_callid_t rid, ipc_call_t *request) |
{ |
int fd = IPC_GET_ARG1(*request); |
659,17 → 772,18 |
fibril_mutex_lock(&file->lock); |
int fs_phone = vfs_grab_phone(file->node->fs_handle); |
/* Make a VFS_OUT_SYMC request at the destination FS server. */ |
/* Make a VFS_SYMC request at the destination FS server. */ |
aid_t msg; |
ipc_call_t answer; |
msg = async_send_2(fs_phone, VFS_OUT_SYNC, file->node->dev_handle, |
file->node->index, &answer); |
msg = async_send_2(fs_phone, IPC_GET_METHOD(*request), |
file->node->dev_handle, file->node->index, &answer); |
vfs_release_phone(fs_phone); |
/* Wait for reply from the FS server. */ |
ipcarg_t rc; |
async_wait_for(msg, &rc); |
vfs_release_phone(fs_phone); |
fibril_mutex_unlock(&file->lock); |
ipc_answer_0(rid, rc); |
691,19 → 805,21 |
* the same open file at a time. |
*/ |
fibril_mutex_lock(&file->lock); |
int fs_phone = vfs_grab_phone(file->node->fs_handle); |
/* Make a VFS_OUT_CLOSE request at the destination FS server. */ |
/* Make a VFS_CLOSE request at the destination FS server. */ |
aid_t msg; |
ipc_call_t answer; |
msg = async_send_2(fs_phone, VFS_OUT_CLOSE, file->node->dev_handle, |
file->node->index, &answer); |
msg = async_send_2(fs_phone, IPC_GET_METHOD(*request), |
file->node->dev_handle, file->node->index, &answer); |
vfs_release_phone(fs_phone); |
/* Wait for reply from the FS server. */ |
ipcarg_t rc; |
async_wait_for(msg, &rc); |
vfs_release_phone(fs_phone); |
fibril_mutex_unlock(&file->lock); |
int retval = IPC_GET_ARG1(answer); |
783,7 → 899,7 |
ipc_call_t answer; |
if (!read && file->append) |
file->pos = file->node->size; |
msg = async_send_3(fs_phone, read ? VFS_OUT_READ : VFS_OUT_WRITE, |
msg = async_send_3(fs_phone, IPC_GET_METHOD(*request), |
file->node->dev_handle, file->node->index, file->pos, &answer); |
/* |
794,12 → 910,12 |
*/ |
ipc_forward_fast(callid, fs_phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME); |
vfs_release_phone(fs_phone); |
/* Wait for reply from the FS server. */ |
ipcarg_t rc; |
async_wait_for(msg, &rc); |
vfs_release_phone(fs_phone); |
size_t bytes = IPC_GET_ARG1(answer); |
if (file->node->type == VFS_NODE_DIRECTORY) |
897,7 → 1013,7 |
int fs_phone; |
fs_phone = vfs_grab_phone(fs_handle); |
rc = async_req_3_0(fs_phone, VFS_OUT_TRUNCATE, (ipcarg_t)dev_handle, |
rc = async_req_3_0(fs_phone, VFS_TRUNCATE, (ipcarg_t)dev_handle, |
(ipcarg_t)index, (ipcarg_t)size); |
vfs_release_phone(fs_phone); |
return (int)rc; |
927,106 → 1043,6 |
ipc_answer_0(rid, (ipcarg_t)rc); |
} |
void vfs_fstat(ipc_callid_t rid, ipc_call_t *request) |
{ |
int fd = IPC_GET_ARG1(*request); |
size_t size = IPC_GET_ARG2(*request); |
ipcarg_t rc; |
vfs_file_t *file = vfs_file_get(fd); |
if (!file) { |
ipc_answer_0(rid, ENOENT); |
return; |
} |
ipc_callid_t callid; |
if (!ipc_data_read_receive(&callid, NULL)) { |
ipc_answer_0(callid, EINVAL); |
ipc_answer_0(rid, EINVAL); |
return; |
} |
fibril_mutex_lock(&file->lock); |
int fs_phone = vfs_grab_phone(file->node->fs_handle); |
aid_t msg; |
msg = async_send_3(fs_phone, VFS_OUT_STAT, file->node->dev_handle, |
file->node->index, true, NULL); |
ipc_forward_fast(callid, fs_phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME); |
async_wait_for(msg, &rc); |
vfs_release_phone(fs_phone); |
fibril_mutex_unlock(&file->lock); |
ipc_answer_0(rid, rc); |
} |
void vfs_stat(ipc_callid_t rid, ipc_call_t *request) |
{ |
size_t len; |
ipc_callid_t callid; |
if (!ipc_data_write_receive(&callid, &len)) { |
ipc_answer_0(callid, EINVAL); |
ipc_answer_0(rid, EINVAL); |
return; |
} |
char *path = malloc(len + 1); |
if (!path) { |
ipc_answer_0(callid, ENOMEM); |
ipc_answer_0(rid, ENOMEM); |
return; |
} |
int rc; |
if ((rc = ipc_data_write_finalize(callid, path, len))) { |
ipc_answer_0(rid, rc); |
free(path); |
return; |
} |
path[len] = '\0'; |
if (!ipc_data_read_receive(&callid, NULL)) { |
free(path); |
ipc_answer_0(callid, EINVAL); |
ipc_answer_0(rid, EINVAL); |
return; |
} |
vfs_lookup_res_t lr; |
fibril_rwlock_read_lock(&namespace_rwlock); |
rc = vfs_lookup_internal(path, L_NONE, &lr, NULL); |
free(path); |
if (rc != EOK) { |
fibril_rwlock_read_unlock(&namespace_rwlock); |
ipc_answer_0(callid, rc); |
ipc_answer_0(rid, rc); |
return; |
} |
vfs_node_t *node = vfs_node_get(&lr); |
if (!node) { |
fibril_rwlock_read_unlock(&namespace_rwlock); |
ipc_answer_0(callid, ENOMEM); |
ipc_answer_0(rid, ENOMEM); |
return; |
} |
fibril_rwlock_read_unlock(&namespace_rwlock); |
int fs_phone = vfs_grab_phone(node->fs_handle); |
aid_t msg; |
msg = async_send_3(fs_phone, VFS_OUT_STAT, node->dev_handle, |
node->index, false, NULL); |
ipc_forward_fast(callid, fs_phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME); |
ipcarg_t rv; |
async_wait_for(msg, &rv); |
vfs_release_phone(fs_phone); |
ipc_answer_0(rid, rv); |
vfs_node_put(node); |
} |
void vfs_mkdir(ipc_callid_t rid, ipc_call_t *request) |
{ |
int mode = IPC_GET_ARG1(*request); |
1101,12 → 1117,12 |
/* |
* The name has already been unlinked by vfs_lookup_internal(). |
* We have to get and put the VFS node to ensure that it is |
* VFS_OUT_DESTROY'ed after the last reference to it is dropped. |
* VFS_DESTROY'ed after the last reference to it is dropped. |
*/ |
vfs_node_t *node = vfs_node_get(&lr); |
fibril_mutex_lock(&nodes_mutex); |
futex_down(&nodes_futex); |
node->lnkcnt--; |
fibril_mutex_unlock(&nodes_mutex); |
futex_up(&nodes_futex); |
fibril_rwlock_write_unlock(&namespace_rwlock); |
vfs_node_put(node); |
ipc_answer_0(rid, EOK); |
1255,9 → 1271,9 |
free(new); |
return; |
} |
fibril_mutex_lock(&nodes_mutex); |
futex_down(&nodes_futex); |
new_node->lnkcnt--; |
fibril_mutex_unlock(&nodes_mutex); |
futex_up(&nodes_futex); |
break; |
default: |
fibril_rwlock_write_unlock(&namespace_rwlock); |
1277,9 → 1293,9 |
free(new); |
return; |
} |
fibril_mutex_lock(&nodes_mutex); |
futex_down(&nodes_futex); |
old_node->lnkcnt++; |
fibril_mutex_unlock(&nodes_mutex); |
futex_up(&nodes_futex); |
/* Destroy the link for the old name. */ |
rc = vfs_lookup_internal(oldc, L_UNLINK, NULL, NULL); |
if (rc != EOK) { |
1292,9 → 1308,9 |
free(new); |
return; |
} |
fibril_mutex_lock(&nodes_mutex); |
futex_down(&nodes_futex); |
old_node->lnkcnt--; |
fibril_mutex_unlock(&nodes_mutex); |
futex_up(&nodes_futex); |
fibril_rwlock_write_unlock(&namespace_rwlock); |
vfs_node_put(old_node); |
if (new_node) |
/branches/dd/uspace/srv/vfs/vfs_register.c |
---|
52,9 → 52,8 |
#include <atomic.h> |
#include "vfs.h" |
FIBRIL_CONDVAR_INITIALIZE(fs_head_cv); |
FIBRIL_MUTEX_INITIALIZE(fs_head_lock); |
LIST_INITIALIZE(fs_head); |
link_t fs_head; |
atomic_t fs_handle_next = { |
.count = 1 |
269,7 → 268,6 |
fs_info->fs_handle = (fs_handle_t) atomic_postinc(&fs_handle_next); |
ipc_answer_1(rid, EOK, (ipcarg_t) fs_info->fs_handle); |
fibril_condvar_broadcast(&fs_head_cv); |
fibril_mutex_unlock(&fs_head_lock); |
dprintf("\"%.*s\" filesystem successfully registered, handle=%d.\n", |
285,14 → 283,13 |
*/ |
int vfs_grab_phone(fs_handle_t handle) |
{ |
int phone; |
/* |
* For now, we don't try to be very clever and very fast. We simply |
* lookup the phone in the fs_head list and duplicate it. The duplicate |
* phone will be returned to the client and the client will use it for |
* communication. In the future, we should cache the connections so |
* that they do not have to be reestablished over and over again. |
* For now, we don't try to be very clever and very fast. |
* We simply lookup the phone in the fs_head list. We currently don't |
* open any additional phones (even though that itself would be pretty |
* straightforward; housekeeping multiple open phones to a FS task would |
* be more demanding). Instead, we simply take the respective |
* phone_futex and keep it until vfs_release_phone(). |
*/ |
fibril_mutex_lock(&fs_head_lock); |
link_t *cur; |
302,11 → 299,7 |
if (fs->fs_handle == handle) { |
fibril_mutex_unlock(&fs_head_lock); |
fibril_mutex_lock(&fs->phone_lock); |
phone = ipc_connect_me_to(fs->phone, 0, 0, 0); |
fibril_mutex_unlock(&fs->phone_lock); |
assert(phone > 0); |
return phone; |
return fs->phone; |
} |
} |
fibril_mutex_unlock(&fs_head_lock); |
313,14 → 306,31 |
return 0; |
} |
/** Tell VFS that the phone is not needed anymore. |
/** Tell VFS that the phone is in use for any request. |
* |
* @param phone Phone to FS task. |
*/ |
void vfs_release_phone(int phone) |
{ |
/* TODO: implement connection caching */ |
ipc_hangup(phone); |
bool found = false; |
fibril_mutex_lock(&fs_head_lock); |
link_t *cur; |
for (cur = fs_head.next; cur != &fs_head; cur = cur->next) { |
fs_info_t *fs = list_get_instance(cur, fs_info_t, fs_link); |
if (fs->phone == phone) { |
found = true; |
fibril_mutex_unlock(&fs_head_lock); |
fibril_mutex_unlock(&fs->phone_lock); |
return; |
} |
} |
fibril_mutex_unlock(&fs_head_lock); |
/* |
* Not good to get here. |
*/ |
assert(found == true); |
} |
/** Convert file system name to its handle. |
/branches/dd/uspace/srv/vfs/vfs.h |
---|
36,6 → 36,7 |
#include <ipc/ipc.h> |
#include <adt/list.h> |
#include <fibril_sync.h> |
#include <futex.h> |
#include <sys/types.h> |
#include <devmap.h> |
#include <bool.h> |
144,10 → 145,8 |
off_t pos; |
} vfs_file_t; |
extern fibril_mutex_t nodes_mutex; |
extern futex_t nodes_futex; |
extern fibril_condvar_t fs_head_cv; |
extern fibril_mutex_t fs_head_lock; |
extern link_t fs_head; /**< List of registered file systems. */ |
extern vfs_pair_t rootfs; /**< Root file system. */ |
159,7 → 158,7 |
size_t len; /**< Number of characters in this PLB entry. */ |
} plb_entry_t; |
extern fibril_mutex_t plb_mutex;/**< Mutex protecting plb and plb_head. */ |
extern futex_t plb_futex; /**< Futex protecting plb and plb_head. */ |
extern uint8_t *plb; /**< Path Lookup Buffer */ |
extern link_t plb_head; /**< List of active PLB entries. */ |
194,19 → 193,19 |
extern void vfs_node_addref(vfs_node_t *); |
extern void vfs_node_delref(vfs_node_t *); |
extern void vfs_process_pending_mount(void); |
extern void vfs_register(ipc_callid_t, ipc_call_t *); |
extern void vfs_mount(ipc_callid_t, ipc_call_t *); |
extern void vfs_open(ipc_callid_t, ipc_call_t *); |
extern void vfs_open_node(ipc_callid_t, ipc_call_t *); |
extern void vfs_device(ipc_callid_t, ipc_call_t *); |
extern void vfs_sync(ipc_callid_t, ipc_call_t *); |
extern void vfs_node(ipc_callid_t, ipc_call_t *); |
extern void vfs_close(ipc_callid_t, ipc_call_t *); |
extern void vfs_read(ipc_callid_t, ipc_call_t *); |
extern void vfs_write(ipc_callid_t, ipc_call_t *); |
extern void vfs_seek(ipc_callid_t, ipc_call_t *); |
extern void vfs_truncate(ipc_callid_t, ipc_call_t *); |
extern void vfs_fstat(ipc_callid_t, ipc_call_t *); |
extern void vfs_fstat(ipc_callid_t, ipc_call_t *); |
extern void vfs_stat(ipc_callid_t, ipc_call_t *); |
extern void vfs_mkdir(ipc_callid_t, ipc_call_t *); |
extern void vfs_unlink(ipc_callid_t, ipc_call_t *); |
extern void vfs_rename(ipc_callid_t, ipc_call_t *); |
/branches/dd/uspace/srv/vfs/vfs_node.c |
---|
38,6 → 38,7 |
#include "vfs.h" |
#include <stdlib.h> |
#include <string.h> |
#include <futex.h> |
#include <fibril_sync.h> |
#include <adt/hash_table.h> |
#include <assert.h> |
44,8 → 45,8 |
#include <async.h> |
#include <errno.h> |
/** Mutex protecting the VFS node hash table. */ |
FIBRIL_MUTEX_INITIALIZE(nodes_mutex); |
/** Futex protecting the VFS node hash table. */ |
futex_t nodes_futex = FUTEX_INITIALIZER; |
#define NODES_BUCKETS_LOG 8 |
#define NODES_BUCKETS (1 << NODES_BUCKETS_LOG) |
88,9 → 89,9 |
*/ |
void vfs_node_addref(vfs_node_t *node) |
{ |
fibril_mutex_lock(&nodes_mutex); |
futex_down(&nodes_futex); |
_vfs_node_addref(node); |
fibril_mutex_unlock(&nodes_mutex); |
futex_up(&nodes_futex); |
} |
/** Decrement reference count of a VFS node. |
104,7 → 105,7 |
bool free_vfs_node = false; |
bool free_fs_node = false; |
fibril_mutex_lock(&nodes_mutex); |
futex_down(&nodes_futex); |
if (node->refcnt-- == 1) { |
/* |
* We are dropping the last reference to this node. |
120,7 → 121,7 |
if (!node->lnkcnt) |
free_fs_node = true; |
} |
fibril_mutex_unlock(&nodes_mutex); |
futex_up(&nodes_futex); |
if (free_fs_node) { |
/* |
129,7 → 130,7 |
*/ |
int phone = vfs_grab_phone(node->fs_handle); |
ipcarg_t rc; |
rc = async_req_2_0(phone, VFS_OUT_DESTROY, |
rc = async_req_2_0(phone, VFS_DESTROY, |
(ipcarg_t)node->dev_handle, (ipcarg_t)node->index); |
assert(rc == EOK); |
vfs_release_phone(phone); |
160,12 → 161,12 |
link_t *tmp; |
vfs_node_t *node; |
fibril_mutex_lock(&nodes_mutex); |
futex_down(&nodes_futex); |
tmp = hash_table_find(&nodes, key); |
if (!tmp) { |
node = (vfs_node_t *) malloc(sizeof(vfs_node_t)); |
if (!node) { |
fibril_mutex_unlock(&nodes_mutex); |
futex_up(&nodes_futex); |
return NULL; |
} |
memset(node, 0, sizeof(vfs_node_t)); |
192,7 → 193,7 |
assert(node->type == result->type || result->type == VFS_NODE_UNKNOWN); |
_vfs_node_addref(node); |
fibril_mutex_unlock(&nodes_mutex); |
futex_up(&nodes_futex); |
return node; |
} |
/branches/dd/uspace/srv/vfs/vfs_lookup.c |
---|
42,14 → 42,14 |
#include <string.h> |
#include <stdarg.h> |
#include <bool.h> |
#include <fibril_sync.h> |
#include <futex.h> |
#include <adt/list.h> |
#include <vfs/canonify.h> |
#define min(a, b) ((a) < (b) ? (a) : (b)) |
FIBRIL_MUTEX_INITIALIZE(plb_mutex); |
LIST_INITIALIZE(plb_head); /**< PLB entry ring buffer. */ |
futex_t plb_futex = FUTEX_INITIALIZER; |
link_t plb_head; /**< PLB entry ring buffer. */ |
uint8_t *plb = NULL; |
/** Perform a path lookup. |
92,7 → 92,7 |
va_end(ap); |
} |
fibril_mutex_lock(&plb_mutex); |
futex_down(&plb_futex); |
plb_entry_t entry; |
link_initialize(&entry.plb_link); |
119,7 → 119,7 |
/* |
* The buffer cannot absorb the path. |
*/ |
fibril_mutex_unlock(&plb_mutex); |
futex_up(&plb_futex); |
return ELIMIT; |
} |
} else { |
127,7 → 127,7 |
/* |
* The buffer cannot absorb the path. |
*/ |
fibril_mutex_unlock(&plb_mutex); |
futex_up(&plb_futex); |
return ELIMIT; |
} |
} |
146,7 → 146,7 |
*/ |
list_append(&entry.plb_link, &plb_head); |
fibril_mutex_unlock(&plb_mutex); |
futex_up(&plb_futex); |
/* |
* Copy the path into PLB. |
159,16 → 159,16 |
ipc_call_t answer; |
int phone = vfs_grab_phone(root->fs_handle); |
aid_t req = async_send_5(phone, VFS_OUT_LOOKUP, (ipcarg_t) first, |
aid_t req = async_send_5(phone, VFS_LOOKUP, (ipcarg_t) first, |
(ipcarg_t) (first + len - 1) % PLB_SIZE, |
(ipcarg_t) root->dev_handle, (ipcarg_t) lflag, (ipcarg_t) index, |
&answer); |
vfs_release_phone(phone); |
ipcarg_t rc; |
async_wait_for(req, &rc); |
vfs_release_phone(phone); |
fibril_mutex_lock(&plb_mutex); |
futex_down(&plb_futex); |
list_remove(&entry.plb_link); |
/* |
* Erasing the path from PLB will come handy for debugging purposes. |
175,7 → 175,7 |
*/ |
memset(&plb[first], 0, cnt1); |
memset(plb, 0, cnt2); |
fibril_mutex_unlock(&plb_mutex); |
futex_up(&plb_futex); |
if ((rc == EOK) && (result)) { |
result->triplet.fs_handle = (fs_handle_t) IPC_GET_ARG1(answer); |
204,14 → 204,14 |
int phone = vfs_grab_phone(result->triplet.fs_handle); |
ipc_call_t answer; |
aid_t req = async_send_2(phone, VFS_OUT_OPEN_NODE, |
aid_t req = async_send_2(phone, VFS_OPEN_NODE, |
(ipcarg_t) result->triplet.dev_handle, |
(ipcarg_t) result->triplet.index, &answer); |
vfs_release_phone(phone); |
ipcarg_t rc; |
async_wait_for(req, &rc); |
vfs_release_phone(phone); |
if (rc == EOK) { |
result->size = (size_t) IPC_GET_ARG1(answer); |
/branches/dd/uspace/srv/vfs/vfs_file.c |
---|
57,7 → 57,7 |
* first VFS_OPEN operation. |
* |
* This resource being per-connection and, in the first place, per-fibril, we |
* don't need to protect it by a mutex. |
* don't need to protect it by a futex. |
*/ |
fibril_local vfs_file_t **files = NULL; |
/branches/dd/uspace/app/bdsh/input.c |
---|
147,10 → 147,8 |
{ |
char line[INPUT_MAX]; |
fflush(stdout); |
console_set_style(fphone(stdout), STYLE_EMPHASIS); |
printf("%s", usr->prompt); |
fflush(stdout); |
console_set_style(fphone(stdout), STYLE_NORMAL); |
read_line(line, INPUT_MAX); |
/branches/dd/uspace/app/bdsh/cmds/modules/bdd/bdd.c |
---|
102,7 → 102,7 |
return CMD_FAILURE; |
} |
rc = block_cache_init(handle, BLOCK_SIZE, 2, CACHE_MODE_WB); |
rc = block_cache_init(handle, BLOCK_SIZE, 2); |
if (rc != EOK) { |
printf("Error: could not init block cache.\n"); |
return CMD_FAILURE; |
/branches/dd/uspace/app/bdsh/cmds/modules/ls/ls.c |
---|
50,9 → 50,48 |
static char *cmdname = "ls"; |
static inline off_t flen(const char *f) |
{ |
int fd; |
off_t size; |
fd = open(f, O_RDONLY); |
if (fd == -1) |
return 0; |
size = lseek(fd, 0, SEEK_END); |
close(fd); |
if (size < 0) |
size = 0; |
return size; |
} |
static unsigned int ls_scope(const char *path) |
{ |
int fd; |
DIR *dirp; |
dirp = opendir(path); |
if (dirp) { |
closedir(dirp); |
return LS_DIR; |
} |
fd = open(path, O_RDONLY); |
if (fd > 0) { |
close(fd); |
return LS_FILE; |
} |
return LS_BOGUS; |
} |
static void ls_scan_dir(const char *d, DIR *dirp) |
{ |
struct dirent *dp; |
unsigned int scope; |
char *buff; |
if (! dirp) |
69,7 → 108,20 |
/* Don't worry if inserting a double slash, this will be fixed by |
* absolutize() later with subsequent calls to open() or readdir() */ |
snprintf(buff, PATH_MAX - 1, "%s/%s", d, dp->d_name); |
ls_print(dp->d_name, buff); |
scope = ls_scope(buff); |
switch (scope) { |
case LS_DIR: |
ls_print_dir(dp->d_name); |
break; |
case LS_FILE: |
ls_print_file(dp->d_name, buff); |
break; |
case LS_BOGUS: |
/* Odd chance it was deleted from the time readdir() found |
* it and the time that it was scoped */ |
printf("ls: skipping bogus node %s\n", dp->d_name); |
break; |
} |
} |
free(buff); |
77,7 → 129,7 |
return; |
} |
/* ls_print currently does nothing more than print the entry. |
/* ls_print_* currently does nothing more than print the entry. |
* in the future, we will likely pass the absolute path, and |
* some sort of ls_options structure that controls how each |
* entry is printed and what is printed about it. |
84,23 → 136,17 |
* |
* Now we just print basic DOS style lists */ |
static void ls_print(const char *name, const char *pathname) |
static void ls_print_dir(const char *d) |
{ |
struct stat s; |
int rc; |
printf("%-40s\t<dir>\n", d); |
if (rc = stat(pathname, &s)) { |
/* Odd chance it was deleted from the time readdir() found it */ |
printf("ls: skipping bogus node %s\n", pathname); |
printf("rc=%d\n", rc); |
return; |
} |
if (s.is_file) |
printf("%-40s\t%llu\n", name, (long long) s.size); |
else |
printf("%-40s\n", name); |
return; |
} |
static void ls_print_file(const char *name, const char *pathname) |
{ |
printf("%-40s\t%llu\n", name, (long long) flen(pathname)); |
return; |
} |
120,7 → 166,7 |
int cmd_ls(char **argv) |
{ |
unsigned int argc; |
struct stat s; |
unsigned int scope; |
char *buff; |
DIR *dirp; |
138,17 → 184,19 |
else |
str_cpy(buff, PATH_MAX, argv[1]); |
if (stat(buff, &s)) { |
scope = ls_scope(buff); |
switch (scope) { |
case LS_BOGUS: |
cli_error(CL_ENOENT, buff); |
free(buff); |
return CMD_FAILURE; |
} |
if (s.is_file) { |
ls_print(buff, buff); |
} else { |
case LS_FILE: |
ls_print_file(buff, buff); |
break; |
case LS_DIR: |
dirp = opendir(buff); |
if (!dirp) { |
if (! dirp) { |
/* May have been deleted between scoping it and opening it */ |
cli_error(CL_EFAIL, "Could not stat %s", buff); |
free(buff); |
156,6 → 204,7 |
} |
ls_scan_dir(buff, dirp); |
closedir(dirp); |
break; |
} |
free(buff); |
/branches/dd/uspace/app/bdsh/cmds/modules/ls/ls.h |
---|
9,7 → 9,8 |
static unsigned int ls_scope(const char *); |
static void ls_scan_dir(const char *, DIR *); |
static void ls_print(const char *, const char *); |
static void ls_print_dir(const char *); |
static void ls_print_file(const char *, const char *); |
#endif /* LS_H */ |
/branches/dd/uspace/app/bdsh/exec.c |
---|
112,9 → 112,7 |
unsigned int try_exec(char *cmd, char **argv) |
{ |
task_id_t tid; |
task_exit_t texit; |
char *tmp; |
int retval; |
tmp = str_dup(find_command(cmd)); |
free(found); |
127,12 → 125,6 |
return 1; |
} |
task_wait(tid, &texit, &retval); |
if (texit != TASK_EXIT_NORMAL) { |
printf("Command failed (unexpectedly terminated).\n"); |
} else if (retval != 0) { |
printf("Command failed (return value %d).\n", retval); |
} |
task_wait(tid); |
return 0; |
} |
/branches/dd/uspace/app/bdsh/util.c |
---|
53,6 → 53,14 |
* string */ |
unsigned int cli_set_prompt(cliuser_t *usr) |
{ |
usr->prompt = (char *) realloc(usr->prompt, PATH_MAX); |
if (NULL == usr->prompt) { |
cli_error(CL_ENOMEM, "Can not allocate prompt"); |
cli_errno = CL_ENOMEM; |
return 1; |
} |
memset(usr->prompt, 0, sizeof(usr->prompt)); |
usr->cwd = (char *) realloc(usr->cwd, PATH_MAX); |
if (NULL == usr->cwd) { |
cli_error(CL_ENOMEM, "Can not allocate cwd"); |
59,11 → 67,13 |
cli_errno = CL_ENOMEM; |
return 1; |
} |
if (!getcwd(usr->cwd, PATH_MAX)) |
memset(usr->cwd, 0, sizeof(usr->cwd)); |
usr->cwd = getcwd(usr->cwd, PATH_MAX - 1); |
if (NULL == usr->cwd) |
snprintf(usr->cwd, PATH_MAX, "(unknown)"); |
if (usr->prompt) |
free(usr->prompt); |
asprintf(&usr->prompt, "%s # ", usr->cwd); |
return 0; |
/branches/dd/uspace/app/init/init.c |
---|
41,13 → 41,11 |
#include <bool.h> |
#include <errno.h> |
#include <fcntl.h> |
#include <sys/stat.h> |
#include <task.h> |
#include <malloc.h> |
#include <macros.h> |
#include <string.h> |
#include <devmap.h> |
#include <config.h> |
#include "init.h" |
static void info_print(void) |
57,31 → 55,31 |
static bool mount_root(const char *fstype) |
{ |
int rc = -1; |
char *opts = ""; |
const char *root_dev = "initrd"; |
if (str_cmp(fstype, "tmpfs") == 0) |
opts = "restore"; |
int rc = mount(fstype, "/", root_dev, opts, IPC_FLAG_BLOCKING); |
switch (rc) { |
case EOK: |
printf(NAME ": Root filesystem mounted, %s at %s\n", |
fstype, root_dev); |
break; |
case EBUSY: |
printf(NAME ": Root filesystem already mounted\n"); |
return false; |
case ELIMIT: |
printf(NAME ": Unable to mount root filesystem\n"); |
return false; |
case ENOENT: |
printf(NAME ": Unknown filesystem type (%s)\n", fstype); |
return false; |
default: |
printf(NAME ": Error mounting root filesystem (%d)\n", rc); |
return false; |
while (rc < 0) { |
rc = mount(fstype, "/", root_dev, opts, IPC_FLAG_BLOCKING); |
switch (rc) { |
case EOK: |
printf(NAME ": Root filesystem mounted, %s at %s\n", |
fstype, root_dev); |
break; |
case EBUSY: |
printf(NAME ": Root filesystem already mounted\n"); |
break; |
case ELIMIT: |
printf(NAME ": Unable to mount root filesystem\n"); |
return false; |
case ENOENT: |
printf(NAME ": Unknown filesystem type (%s)\n", fstype); |
return false; |
} |
} |
return true; |
89,39 → 87,27 |
static bool mount_devfs(void) |
{ |
char null[MAX_DEVICE_NAME]; |
int null_id = devmap_null_create(); |
int rc = -1; |
if (null_id == -1) { |
printf(NAME ": Unable to create null device\n"); |
return false; |
while (rc < 0) { |
rc = mount("devfs", "/dev", "null", "", IPC_FLAG_BLOCKING); |
switch (rc) { |
case EOK: |
printf(NAME ": Device filesystem mounted\n"); |
break; |
case EBUSY: |
printf(NAME ": Device filesystem already mounted\n"); |
break; |
case ELIMIT: |
printf(NAME ": Unable to mount device filesystem\n"); |
return false; |
case ENOENT: |
printf(NAME ": Unknown filesystem type (devfs)\n"); |
return false; |
} |
} |
snprintf(null, MAX_DEVICE_NAME, "null%d", null_id); |
int rc = mount("devfs", "/dev", null, "", IPC_FLAG_BLOCKING); |
switch (rc) { |
case EOK: |
printf(NAME ": Device filesystem mounted\n"); |
break; |
case EBUSY: |
printf(NAME ": Device filesystem already mounted\n"); |
devmap_null_destroy(null_id); |
return false; |
case ELIMIT: |
printf(NAME ": Unable to mount device filesystem\n"); |
devmap_null_destroy(null_id); |
return false; |
case ENOENT: |
printf(NAME ": Unknown filesystem type (devfs)\n"); |
devmap_null_destroy(null_id); |
return false; |
default: |
printf(NAME ": Error mounting device filesystem (%d)\n", rc); |
devmap_null_destroy(null_id); |
return false; |
} |
return true; |
} |
128,11 → 114,7 |
static void spawn(char *fname) |
{ |
char *argv[2]; |
struct stat s; |
if (stat(fname, &s) == ENOENT) |
return; |
printf(NAME ": Spawning %s\n", fname); |
argv[0] = fname; |
142,45 → 124,10 |
printf(NAME ": Error spawning %s\n", fname); |
} |
static void srv_start(char *fname) |
{ |
char *argv[2]; |
task_id_t id; |
task_exit_t texit; |
int rc, retval; |
struct stat s; |
if (stat(fname, &s) == ENOENT) |
return; |
printf(NAME ": Starting %s\n", fname); |
argv[0] = fname; |
argv[1] = NULL; |
id = task_spawn(fname, argv); |
if (!id) { |
printf(NAME ": Error spawning %s\n", fname); |
return; |
} |
rc = task_wait(id, &texit, &retval); |
if (rc != EOK) { |
printf(NAME ": Error waiting for %s\n", fname); |
return; |
} |
if (texit != TASK_EXIT_NORMAL || retval != 0) { |
printf(NAME ": Server %s failed to start (returned %d)\n", |
fname, retval); |
} |
} |
static void getvc(char *dev, char *app) |
{ |
char *argv[4]; |
char vc[MAX_DEVICE_NAME]; |
int rc; |
snprintf(vc, MAX_DEVICE_NAME, "/dev/%s", dev); |
187,9 → 134,9 |
printf(NAME ": Spawning getvc on %s\n", vc); |
dev_handle_t handle; |
rc = devmap_device_get_handle(dev, &handle, IPC_FLAG_BLOCKING); |
devmap_device_get_handle(dev, &handle, IPC_FLAG_BLOCKING); |
if (rc == EOK) { |
if (handle >= 0) { |
argv[0] = "/app/getvc"; |
argv[1] = vc; |
argv[2] = app; |
197,25 → 144,10 |
if (!task_spawn("/app/getvc", argv)) |
printf(NAME ": Error spawning getvc on %s\n", vc); |
} else { |
} else |
printf(NAME ": Error waiting on %s\n", vc); |
} |
} |
void mount_data(void) |
{ |
int rc; |
printf("Trying to mount disk0 on /data... "); |
fflush(stdout); |
rc = mount("fat", "/data", "disk0", "wtcache", 0); |
if (rc == EOK) |
printf("OK\n"); |
else |
printf("Failed\n"); |
} |
int main(int argc, char *argv[]) |
{ |
info_print(); |
228,7 → 160,7 |
spawn("/srv/devfs"); |
if (!mount_devfs()) { |
printf(NAME ": Exiting\n"); |
return(NAME ": Exiting\n"); |
return -2; |
} |
237,19 → 169,7 |
spawn("/srv/console"); |
spawn("/srv/fhc"); |
spawn("/srv/obio"); |
/* |
* Start these synchronously so that mount_data() can be |
* non-blocking. |
*/ |
#ifdef CONFIG_START_BD |
srv_start("/srv/ata_bd"); |
srv_start("/srv/gxe_bd"); |
#endif |
#ifdef CONFIG_MOUNT_DATA |
mount_data(); |
#endif |
getvc("vc0", "/app/bdsh"); |
getvc("vc1", "/app/bdsh"); |
getvc("vc2", "/app/bdsh"); |
/branches/dd/uspace/app/init/Makefile |
---|
34,7 → 34,6 |
include $(LIBC_PREFIX)/Makefile.toolchain |
CFLAGS += -I../../.. |
LIBS = $(LIBC_PREFIX)/libc.a |
## Sources |
/branches/dd/uspace/app/tester/mm/malloc1.c |
---|
File deleted |
/branches/dd/uspace/app/tester/mm/malloc1.def |
---|
File deleted |
/branches/dd/uspace/app/tester/console/console1.c |
---|
46,78 → 46,65 |
[COLOR_WHITE] = "white" |
}; |
char *test_console1(void) |
char * test_console1(bool quiet) |
{ |
if (!test_quiet) { |
printf("Style test: "); |
fflush(stdout); |
console_set_style(fphone(stdout), STYLE_NORMAL); |
printf("normal "); |
fflush(stdout); |
console_set_style(fphone(stdout), STYLE_EMPHASIS); |
printf("emphasized"); |
fflush(stdout); |
console_set_style(fphone(stdout), STYLE_NORMAL); |
printf(".\n"); |
unsigned int i; |
unsigned int j; |
printf("\nForeground color test:\n"); |
for (j = 0; j < 2; j++) { |
for (i = COLOR_BLACK; i <= COLOR_WHITE; i++) { |
fflush(stdout); |
console_set_color(fphone(stdout), i, COLOR_WHITE, |
j ? CATTR_BRIGHT : 0); |
printf(" %s ", color_name[i]); |
} |
fflush(stdout); |
console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0); |
putchar('\n'); |
int i, j; |
printf("Style test: "); |
console_set_style(fphone(stdout), STYLE_NORMAL); |
printf("normal "); |
console_set_style(fphone(stdout), STYLE_EMPHASIS); |
printf("emphasized"); |
console_set_style(fphone(stdout), STYLE_NORMAL); |
printf(".\n"); |
printf("Foreground color test:\n"); |
for (j = 0; j < 2; j++) { |
for (i = COLOR_BLACK; i <= COLOR_WHITE; i++) { |
console_set_color(fphone(stdout), i, COLOR_WHITE, |
j ? CATTR_BRIGHT : 0); |
printf(" %s ", color_name[i]); |
} |
printf("\nBackground color test:\n"); |
for (j = 0; j < 2; j++) { |
for (i = COLOR_BLACK; i <= COLOR_WHITE; i++) { |
fflush(stdout); |
console_set_color(fphone(stdout), COLOR_WHITE, i, |
j ? CATTR_BRIGHT : 0); |
printf(" %s ", color_name[i]); |
} |
fflush(stdout); |
console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0); |
putchar('\n'); |
} |
printf("\nRGB colors test:\n"); |
for (i = 0; i < 255; i += 16) { |
fflush(stdout); |
console_set_rgb_color(fphone(stdout), 0xffffff, i << 16); |
putchar('X'); |
} |
fflush(stdout); |
console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0); |
putchar('\n'); |
for (i = 0; i < 255; i += 16) { |
fflush(stdout); |
console_set_rgb_color(fphone(stdout), 0xffffff, i << 8); |
putchar('X'); |
} |
printf("Background color test:\n"); |
for (j = 0; j < 2; j++) { |
for (i = COLOR_BLACK; i <= COLOR_WHITE; i++) { |
console_set_color(fphone(stdout), COLOR_WHITE, i, |
j ? CATTR_BRIGHT : 0); |
printf(" %s ", color_name[i]); |
} |
fflush(stdout); |
console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0); |
putchar('\n'); |
for (i = 0; i < 255; i += 16) { |
fflush(stdout); |
console_set_rgb_color(fphone(stdout), 0xffffff, i); |
putchar('X'); |
} |
fflush(stdout); |
console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0); |
putchar('\n'); |
} |
printf("Now let's test RGB colors:\n"); |
for (i = 0; i < 255; i += 16) { |
console_set_rgb_color(fphone(stdout), 0xffffff, i << 16); |
putchar('X'); |
} |
console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0); |
putchar('\n'); |
for (i = 0; i < 255; i += 16) { |
console_set_rgb_color(fphone(stdout), 0xffffff, i << 8); |
putchar('X'); |
} |
console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0); |
putchar('\n'); |
for (i = 0; i < 255; i += 16) { |
console_set_rgb_color(fphone(stdout), 0xffffff, i); |
putchar('X'); |
} |
console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0); |
putchar('\n'); |
printf("[press a key]\n"); |
getchar(); |
return NULL; |
} |
/branches/dd/uspace/app/tester/tester.c |
---|
27,10 → 27,10 |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup tester User space tester |
* @brief User space testing infrastructure. |
/** @addtogroup tester User space Tester |
* @brief User space testing infrastructure. |
* @{ |
*/ |
*/ |
/** |
* @file |
*/ |
37,44 → 37,48 |
#include <unistd.h> |
#include <stdio.h> |
#include <string.h> |
#include "tester.h" |
bool test_quiet; |
int test_argc; |
char **test_argv; |
int myservice = 0; |
int phones[MAX_PHONES]; |
int connections[MAX_CONNECTIONS]; |
ipc_callid_t callids[MAX_CONNECTIONS]; |
test_t tests[] = { |
#include "thread/thread1.def" |
#include "print/print1.def" |
#include "print/print2.def" |
#include "print/print3.def" |
#include "print/print4.def" |
#include "console/console1.def" |
#include "stdio/stdio1.def" |
#include "stdio/stdio2.def" |
#include "fault/fault1.def" |
#include "fault/fault2.def" |
#include "vfs/vfs1.def" |
#include "ipc/ping_pong.def" |
#include "ipc/register.def" |
#include "ipc/connect.def" |
#include "ipc/send_async.def" |
#include "ipc/send_sync.def" |
#include "ipc/answer.def" |
#include "ipc/hangup.def" |
#include "ipc/ping_pong.def" |
#include "devmap/devmap1.def" |
#include "loop/loop1.def" |
#include "mm/malloc1.def" |
{NULL, NULL, NULL, false} |
#include "vfs/vfs1.def" |
#include "console/console1.def" |
#include "stdio/stdio1.def" |
#include "stdio/stdio2.def" |
{NULL, NULL, NULL} |
}; |
static bool run_test(test_t *test) |
{ |
printf("%s\t\t%s\n", test->name, test->desc); |
/* Execute the test */ |
char *ret = test->entry(); |
char * ret = test->entry(false); |
if (ret == NULL) { |
printf("\nTest passed\n"); |
printf("Test passed\n\n"); |
return true; |
} |
printf("\n%s\n", ret); |
printf("%s\n\n", ret); |
return false; |
} |
83,12 → 87,11 |
test_t *test; |
unsigned int i = 0; |
unsigned int n = 0; |
printf("\n*** Running all safe tests ***\n\n"); |
for (test = tests; test->name != NULL; test++) { |
if (test->safe) { |
printf("%s (%s)\n", test->name, test->desc); |
if (run_test(test)) |
i++; |
else |
95,52 → 98,64 |
n++; |
} |
} |
printf("\nCompleted, %u tests run, %u passed.\n", i + n, i); |
printf("\nSafe tests completed, %u tests run, %u passed.\n\n", i + n, i); |
} |
static void list_tests(void) |
{ |
size_t len = 0; |
test_t *test; |
for (test = tests; test->name != NULL; test++) { |
if (str_length(test->name) > len) |
len = str_length(test->name); |
} |
char c = 'a'; |
for (test = tests; test->name != NULL; test++) |
printf("%-*s %s%s\n", len, test->name, test->desc, (test->safe ? "" : " (unsafe)")); |
for (test = tests; test->name != NULL; test++, c++) |
printf("%c\t%s\t\t%s%s\n", c, test->name, test->desc, (test->safe ? "" : " (unsafe)")); |
printf("%-*s Run all safe tests\n", len, "*"); |
printf("*\t\t\tRun all safe tests\n"); |
} |
int main(int argc, char *argv[]) |
int main(int argc, char **argv) |
{ |
if (argc < 2) { |
printf("Usage:\n\n"); |
printf("%s <test> [args ...]\n\n", argv[0]); |
printf("Number of arguments: %d\n", argc); |
if (argv) { |
printf("Arguments:"); |
while (*argv) { |
printf(" '%s'", *argv++); |
} |
printf("\n"); |
} |
while (1) { |
char c; |
test_t *test; |
list_tests(); |
return 0; |
} |
test_quiet = false; |
test_argc = argc - 2; |
test_argv = argv + 2; |
if (str_cmp(argv[1], "*") == 0) { |
run_safe_tests(); |
return 0; |
} |
test_t *test; |
for (test = tests; test->name != NULL; test++) { |
if (str_cmp(argv[1], test->name) == 0) { |
return (run_test(test) ? 0 : -1); |
printf("> "); |
fflush(stdout); |
c = getchar(); |
printf("%c\n", c); |
if ((c >= 'a') && (c <= 'z')) { |
for (test = tests; test->name != NULL; test++, c--) |
if (c == 'a') |
break; |
if (test->name == NULL) |
printf("Unknown test\n\n"); |
else |
run_test(test); |
} else if (c == '*') { |
run_safe_tests(); |
} else if (c < 0) { |
/* got EOF */ |
break; |
} else { |
printf("Invalid test\n\n"); |
} |
} |
printf("Unknown test \"%s\"\n", argv[1]); |
return -2; |
return 0; |
} |
/** @} |
/branches/dd/uspace/app/tester/ipc/ping_pong.c |
---|
37,23 → 37,20 |
#define DURATION_SECS 10 |
#define COUNT_GRANULARITY 100 |
char *test_ping_pong(void) |
char *test_ping_pong(bool quiet) |
{ |
TPRINTF("Pinging ns server for %d seconds...", DURATION_SECS); |
printf("Pinging ns server for %d seconds...\n", DURATION_SECS); |
struct timeval start; |
if (gettimeofday(&start, NULL) != 0) { |
TPRINTF("\n"); |
return "Failed getting the time"; |
} |
if (gettimeofday(&start, NULL) != 0) |
return "Failed getting the time."; |
uint64_t count = 0; |
while (true) { |
struct timeval now; |
if (gettimeofday(&now, NULL) != 0) { |
TPRINTF("\n"); |
return "Failed getting the time"; |
} |
if (gettimeofday(&now, NULL) != 0) |
return "Failed getting the time."; |
if (tv_sub(&now, &start) >= DURATION_SECS * 1000000L) |
break; |
62,16 → 59,14 |
for (i = 0; i < COUNT_GRANULARITY; i++) { |
int retval = async_req_0_0(PHONE_NS, NS_PING); |
if (retval != EOK) { |
TPRINTF("\n"); |
return "Failed to send ping message"; |
} |
if (retval != EOK) |
return "Failed to send ping message."; |
} |
count += COUNT_GRANULARITY; |
} |
TPRINTF("OK\nCompleted %llu round trips in %u seconds, %llu rt/s.\n", |
printf("Completed %lu round trips in %u seconds, %lu RT/s.\n", |
count, DURATION_SECS, count / DURATION_SECS); |
return NULL; |
/branches/dd/uspace/app/tester/ipc/send_sync.c |
---|
0,0 → 1,53 |
/* |
* Copyright (c) 2006 Ondrej Palkovsky |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
#include <stdio.h> |
#include <unistd.h> |
#include "../tester.h" |
#include <ipc/ipc.h> |
char * test_send_sync(bool quiet) |
{ |
int phoneid; |
int res; |
char c; |
printf("Select phoneid to send msg: 2-9 (q to skip)\n"); |
do { |
c = getchar(); |
if ((c == 'Q') || (c == 'q')) |
return TEST_SKIPPED; |
} while (c < '2' || c > '9'); |
phoneid = c - '0'; |
printf("Sending msg..."); |
res = ipc_call_sync_0_0(phoneid, 2000); |
printf("done: %d\n", res); |
return NULL; |
} |
/branches/dd/uspace/app/tester/ipc/hangup.c |
---|
0,0 → 1,53 |
/* |
* Copyright (c) 2006 Ondrej Palkovsky |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
#include <stdio.h> |
#include <unistd.h> |
#include <errno.h> |
#include "../tester.h" |
char * test_hangup(bool quiet) |
{ |
char c; |
int res; |
int phoneid; |
printf("Select phoneid to hangup: 2-9 (q to skip)\n"); |
do { |
c = getchar(); |
if ((c == 'Q') || (c == 'q')) |
return TEST_SKIPPED; |
} while (c < '2' || c > '9'); |
phoneid = c - '0'; |
printf("Hanging up..."); |
res = ipc_hangup(phoneid); |
printf("done: %d\n", phoneid); |
return NULL; |
} |
/branches/dd/uspace/app/tester/ipc/send_async.c |
---|
0,0 → 1,57 |
/* |
* Copyright (c) 2006 Ondrej Palkovsky |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
#include <stdio.h> |
#include <unistd.h> |
#include "../tester.h" |
static void callback(void *_private, int retval, ipc_call_t *data) |
{ |
printf("Received response to msg %d - retval: %d.\n", _private, retval); |
} |
char * test_send_async(bool quiet) |
{ |
int phoneid; |
static int msgid = 1; |
char c; |
printf("Select phoneid to send msg: 2-9 (q to skip)\n"); |
do { |
c = getchar(); |
if ((c == 'Q') || (c == 'q')) |
return TEST_SKIPPED; |
} while (c < '2' || c > '9'); |
phoneid = c - '0'; |
ipc_call_async_0(phoneid, 2000, (void *) msgid, callback, 1); |
printf("Async sent - msg %d\n", msgid); |
msgid++; |
return NULL; |
} |
/branches/dd/uspace/app/tester/ipc/connect.c |
---|
28,46 → 28,32 |
#include <stdio.h> |
#include <unistd.h> |
#include <atomic.h> |
#include "../tester.h" |
static atomic_t finish; |
static void callback(void *priv, int retval, ipc_call_t *data) |
char * test_connect(bool quiet) |
{ |
atomic_set(&finish, 1); |
} |
char c; |
int svc; |
int phid; |
char *test_connect(void) |
{ |
TPRINTF("Connecting to %u...", IPC_TEST_SERVICE); |
int phone = ipc_connect_me_to(PHONE_NS, IPC_TEST_SERVICE, 0, 0); |
if (phone > 0) { |
TPRINTF("phoneid %d\n", phone); |
} else { |
TPRINTF("\n"); |
return "ipc_connect_me_to() failed"; |
} |
printf("Choose one service: 0:10000....9:10009 (q to skip)\n"); |
do { |
c = getchar(); |
if ((c == 'Q') || (c == 'q')) |
return TEST_SKIPPED; |
} while (c < '0' || c > '9'); |
printf("Sending synchronous message...\n"); |
int retval = ipc_call_sync_0_0(phone, IPC_TEST_METHOD); |
TPRINTF("Received response to synchronous message\n"); |
svc = IPC_TEST_START + c - '0'; |
if (svc == myservice) |
return "Currently cannot connect to myself, update test"; |
TPRINTF("Sending asynchronous message...\n"); |
atomic_set(&finish, 0); |
ipc_call_async_0(phone, IPC_TEST_METHOD, NULL, callback, 1); |
while (atomic_get(&finish) != 1) |
TPRINTF("."); |
TPRINTF("Received response to asynchronous message\n"); |
printf("Connecting to %d..", svc); |
phid = ipc_connect_me_to(PHONE_NS, svc, 0, 0); |
if (phid > 0) { |
printf("phoneid: %d\n", phid); |
phones[phid] = 1; |
} else |
return "Error"; |
TPRINTF("Hanging up..."); |
retval = ipc_hangup(phone); |
if (retval == 0) { |
TPRINTF("OK\n"); |
} else { |
TPRINTF("\n"); |
return "ipc_hangup() failed"; |
} |
return NULL; |
} |
/branches/dd/uspace/app/tester/ipc/register.c |
---|
32,58 → 32,58 |
#include <errno.h> |
#include "../tester.h" |
#define MAX_CONNECTIONS 50 |
static int connections[MAX_CONNECTIONS]; |
static void client_connection(ipc_callid_t iid, ipc_call_t *icall) |
{ |
unsigned int i; |
TPRINTF("Connected phone %#x accepting\n", icall->in_phone_hash); |
ipc_callid_t callid; |
ipc_call_t call; |
ipcarg_t phonehash = icall->in_phone_hash; |
int retval; |
int i; |
printf("Connected phone: %P, accepting\n", icall->in_phone_hash); |
ipc_answer_0(iid, EOK); |
for (i = 0; i < MAX_CONNECTIONS; i++) { |
for (i = 0; i < 1024; i++) |
if (!connections[i]) { |
connections[i] = icall->in_phone_hash; |
connections[i] = phonehash; |
break; |
} |
} |
while (true) { |
ipc_call_t call; |
ipc_callid_t callid = async_get_call(&call); |
int retval; |
while (1) { |
callid = async_get_call(&call); |
switch (IPC_GET_METHOD(call)) { |
case IPC_M_PHONE_HUNGUP: |
TPRINTF("Phone %#x hung up\n", icall->in_phone_hash); |
printf("Phone (%P) hung up.\n", phonehash); |
retval = 0; |
break; |
case IPC_TEST_METHOD: |
TPRINTF("Received well known message from %#x: %#x\n", |
icall->in_phone_hash, callid); |
ipc_answer_0(callid, EOK); |
break; |
default: |
TPRINTF("Received unknown message from %#x: %#x\n", |
icall->in_phone_hash, callid); |
ipc_answer_0(callid, ENOENT); |
break; |
printf("Received message from %P: %X\n", phonehash, |
callid); |
for (i = 0; i < 1024; i++) |
if (!callids[i]) { |
callids[i] = callid; |
break; |
} |
continue; |
} |
ipc_answer_0(callid, retval); |
} |
} |
char *test_register(void) |
char * test_register(bool quiet) |
{ |
int i; |
async_set_client_connection(client_connection); |
for (i = IPC_TEST_START; i < IPC_TEST_START + 10; i++) { |
ipcarg_t phonead; |
int res = ipc_connect_to_me(PHONE_NS, i, 0, 0, &phonead); |
if (!res) |
break; |
printf("Failed registering as %d..:%d\n", i, res); |
} |
printf("Registered as service: %d\n", i); |
myservice = i; |
ipcarg_t phonead; |
int res = ipc_connect_to_me(PHONE_NS, IPC_TEST_SERVICE, 0, 0, &phonead); |
if (res != 0) |
return "Failed registering IPC service"; |
TPRINTF("Registered as service %u, accepting connections\n", IPC_TEST_SERVICE); |
async_manager(); |
return NULL; |
} |
/branches/dd/uspace/app/tester/ipc/answer.c |
---|
0,0 → 1,76 |
/* |
* Copyright (c) 2006 Ondrej Palkovsky |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
#include <stdio.h> |
#include <unistd.h> |
#include <errno.h> |
#include "../tester.h" |
char * test_answer(bool quiet) |
{ |
int i,cnt, errn = 0; |
char c; |
cnt = 0; |
for (i = 0;i < 50; i++) { |
if (callids[i]) { |
printf("%d: %P\n", cnt, callids[i]); |
cnt++; |
} |
if (cnt >= 10) |
break; |
} |
if (!cnt) |
return NULL; |
printf("Choose message:\n"); |
do { |
c = getchar(); |
} while (c < '0' || (c-'0') >= cnt); |
cnt = c - '0' + 1; |
for (i = 0; cnt; i++) |
if (callids[i]) |
cnt--; |
i -= 1; |
printf("Normal (n) or hangup (h) or error(e) message?\n"); |
do { |
c = getchar(); |
} while (c != 'n' && c != 'h' && c != 'e'); |
if (c == 'n') |
errn = 0; |
else if (c == 'h') |
errn = EHANGUP; |
else if (c == 'e') |
errn = ENOENT; |
printf("Answering %P\n", callids[i]); |
ipc_answer_0(callids[i], errn); |
callids[i] = 0; |
return NULL; |
} |
/branches/dd/uspace/app/tester/ipc/hangup.def |
---|
0,0 → 1,6 |
{ |
"hangup", |
"IPC hangup test", |
&test_hangup, |
true |
}, |
/branches/dd/uspace/app/tester/ipc/send_sync.def |
---|
0,0 → 1,6 |
{ |
"send_sync", |
"IPC send sync message test", |
&test_send_sync, |
true |
}, |
/branches/dd/uspace/app/tester/ipc/send_async.def |
---|
0,0 → 1,6 |
{ |
"send_async", |
"IPC send async message test", |
&test_send_async, |
true |
}, |
/branches/dd/uspace/app/tester/ipc/answer.def |
---|
0,0 → 1,6 |
{ |
"answer", |
"IPC answer message test", |
&test_answer, |
true |
}, |
/branches/dd/uspace/app/tester/devmap/devmap1.c |
---|
0,0 → 1,201 |
/* |
* Copyright (c) 2007 Josef Cejka |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
#include <stdio.h> |
#include <unistd.h> |
#include <ipc/ipc.h> |
#include <ipc/services.h> |
#include <async.h> |
#include <errno.h> |
#include <devmap.h> |
#include "../tester.h" |
#include <time.h> |
#define TEST_DEVICE1 "TestDevice1" |
#define TEST_DEVICE2 "TestDevice2" |
/** Handle requests from clients |
* |
*/ |
static void driver_client_connection(ipc_callid_t iid, ipc_call_t *icall) |
{ |
ipc_callid_t callid; |
ipc_call_t call; |
int retval; |
printf("connected: method=%u arg1=%u, arg2=%u arg3=%u.\n", |
IPC_GET_METHOD(*icall), IPC_GET_ARG1(*icall), IPC_GET_ARG2(*icall), |
IPC_GET_ARG3(*icall)); |
printf("driver_client_connection.\n"); |
ipc_answer_0(iid, EOK); |
/* Ignore parameters, the connection is already opened */ |
while (1) { |
callid = async_get_call(&call); |
retval = EOK; |
printf("method=%u arg1=%u, arg2=%u arg3=%u.\n", |
IPC_GET_METHOD(call), IPC_GET_ARG1(call), |
IPC_GET_ARG2(call), IPC_GET_ARG3(call)); |
switch (IPC_GET_METHOD(call)) { |
case IPC_M_PHONE_HUNGUP: |
/* TODO: Handle hangup */ |
return; |
default: |
printf("Unknown device method %u.\n", |
IPC_GET_METHOD(call)); |
retval = ENOENT; |
} |
ipc_answer_0(callid, retval); |
} |
return; |
} |
static int device_client_fibril(void *arg) |
{ |
int handle; |
int device_phone; |
handle = (int)arg; |
device_phone = devmap_device_connect(handle, 0); |
if (device_phone < 0) { |
printf("Failed to connect to device (handle = %u).\n", |
handle); |
return -1; |
} |
printf("Connected to device.\n"); |
ipc_hangup(device_phone); |
return EOK; |
} |
/** Communication test with device. |
* @param handle handle to tested instance. |
*/ |
static int device_client(int handle) |
{ |
/* fid_t fid; |
ipc_call_t call; |
ipc_callid_t callid; |
fid = fibril_create(device_client_fibril, (void *)handle); |
fibril_add_ready(fid); |
*/ |
return EOK; |
} |
/** Test DevMap from the driver's point of view. |
* |
* |
*/ |
char * test_devmap1(bool quiet) |
{ |
const char *retval = NULL; |
/* Register new driver */ |
int rc = devmap_driver_register("TestDriver", driver_client_connection); |
if (rc < 0) { |
retval = "Error: Cannot register driver.\n"; |
goto out; |
} |
/* Register new device dev1. */ |
dev_handle_t dev1_handle; |
rc = devmap_device_register(TEST_DEVICE1, &dev1_handle); |
if (rc != EOK) { |
retval = "Error: cannot register device.\n"; |
goto out; |
} |
/* |
* Get handle for dev2 (Should fail unless device is already registered |
* by someone else). |
*/ |
dev_handle_t handle; |
rc = devmap_device_get_handle(TEST_DEVICE2, &handle, 0); |
if (rc == EOK) { |
retval = "Error: got handle for dev2 before it was registered.\n"; |
goto out; |
} |
/* Register new device dev2. */ |
dev_handle_t dev2_handle; |
rc = devmap_device_register(TEST_DEVICE2, &dev2_handle); |
if (rc != EOK) { |
retval = "Error: cannot register device dev2.\n"; |
goto out; |
} |
/* Register device dev1 again. */ |
dev_handle_t dev3_handle; |
rc = devmap_device_register(TEST_DEVICE1, &dev3_handle); |
if (rc == EOK) { |
retval = "Error: dev1 registered twice.\n"; |
goto out; |
} |
/* Get handle for dev1. */ |
rc = devmap_device_get_handle(TEST_DEVICE1, &handle, 0); |
if (rc != EOK) { |
retval = "Error: cannot get handle for 'DEVMAP_DEVICE1'.\n"; |
goto out; |
} |
if (handle != dev1_handle) { |
retval = "Error: cannot get handle for 'DEVMAP_DEVICE1'.\n"; |
goto out; |
} |
if (device_client(dev1_handle) != EOK) { |
retval = "Error: failed client test for 'DEVMAP_DEVICE1'.\n"; |
goto out; |
} |
out: |
devmap_hangup_phone(DEVMAP_DRIVER); |
devmap_hangup_phone(DEVMAP_CLIENT); |
return NULL; |
} |
char *test_devmap2(bool quiet) |
{ |
/*TODO: Full automatic test */ |
return NULL; |
} |
char *test_devmap3(bool quiet) |
{ |
/* TODO: allow user to call test functions in random order */ |
return NULL; |
} |
/branches/dd/uspace/app/tester/devmap/devmap1.def |
---|
0,0 → 1,6 |
{ |
"devmap1", |
"DevMap test", |
&test_devmap1, |
true |
}, |
/branches/dd/uspace/app/tester/tester.h |
---|
39,45 → 39,43 |
#include <bool.h> |
#include <ipc/ipc.h> |
#define IPC_TEST_SERVICE 10240 |
#define IPC_TEST_METHOD 2000 |
#define IPC_TEST_START 10000 |
#define MAX_PHONES 20 |
#define MAX_CONNECTIONS 50 |
#define TEST_SKIPPED "Test Skipped" |
extern bool test_quiet; |
extern int test_argc; |
extern char **test_argv; |
extern int myservice; |
extern int phones[MAX_PHONES]; |
extern int connections[MAX_CONNECTIONS]; |
extern ipc_callid_t callids[MAX_CONNECTIONS]; |
#define TPRINTF(format, ...) \ |
{ \ |
if (!test_quiet) { \ |
fprintf(stderr, format, ##__VA_ARGS__); \ |
} \ |
} |
typedef char * (* test_entry_t)(bool); |
typedef char *(*test_entry_t)(void); |
typedef struct { |
char *name; |
char *desc; |
char * name; |
char * desc; |
test_entry_t entry; |
bool safe; |
} test_t; |
extern char *test_thread1(void); |
extern char *test_print1(void); |
extern char *test_print2(void); |
extern char *test_print3(void); |
extern char *test_print4(void); |
extern char *test_console1(void); |
extern char *test_stdio1(void); |
extern char *test_stdio2(void); |
extern char *test_fault1(void); |
extern char *test_fault2(void); |
extern char *test_vfs1(void); |
extern char *test_ping_pong(void); |
extern char *test_register(void); |
extern char *test_connect(void); |
extern char *test_loop1(void); |
extern char *test_malloc1(void); |
extern char * test_thread1(bool quiet); |
extern char * test_print1(bool quiet); |
extern char * test_print4(bool quiet); |
extern char * test_fault1(bool quiet); |
extern char * test_fault2(bool quiet); |
extern char * test_register(bool quiet); |
extern char * test_connect(bool quiet); |
extern char * test_send_async(bool quiet); |
extern char * test_send_sync(bool quiet); |
extern char * test_answer(bool quiet); |
extern char * test_hangup(bool quiet); |
extern char * test_ping_pong(bool quiet); |
extern char * test_devmap1(bool quiet); |
extern char * test_loop1(bool quiet); |
extern char * test_vfs1(bool quiet); |
extern char * test_console1(bool quiet); |
extern char * test_stdio1(bool quiet); |
extern char * test_stdio2(bool quiet); |
extern test_t tests[]; |
/branches/dd/uspace/app/tester/Makefile |
---|
45,20 → 45,22 |
SOURCES = tester.c \ |
thread/thread1.c \ |
print/print1.c \ |
print/print2.c \ |
print/print3.c \ |
print/print4.c \ |
console/console1.c \ |
stdio/stdio1.c \ |
stdio/stdio2.c \ |
fault/fault1.c \ |
fault/fault2.c \ |
vfs/vfs1.c \ |
ipc/ping_pong.c \ |
ipc/register.c \ |
ipc/connect.c \ |
ipc/send_async.c \ |
ipc/send_sync.c \ |
ipc/answer.c \ |
ipc/hangup.c \ |
ipc/ping_pong.c \ |
loop/loop1.c \ |
mm/malloc1.c |
devmap/devmap1.c \ |
console/console1.c \ |
stdio/stdio1.c \ |
stdio/stdio2.c \ |
vfs/vfs1.c |
OBJECTS := $(addsuffix .o,$(basename $(SOURCES))) |
/branches/dd/uspace/app/tester/vfs/vfs1.c |
---|
34,118 → 34,109 |
#include <unistd.h> |
#include <fcntl.h> |
#include <dirent.h> |
#include <devmap.h> |
#include <sys/types.h> |
#include <sys/stat.h> |
#include "../tester.h" |
#define FS_TYPE "tmpfs" |
#define MOUNT_POINT "/tmp" |
#define OPTIONS "" |
#define FLAGS 0 |
char text[] = "O xein', angellein Lakedaimoniois hoti teide " |
"keimetha tois keinon rhemasi peithomenoi."; |
#define TEST_DIRECTORY MOUNT_POINT "/testdir" |
#define TEST_FILE TEST_DIRECTORY "/testfile" |
#define TEST_FILE2 TEST_DIRECTORY "/nextfile" |
#define MAX_DEVICE_NAME 32 |
#define BUF_SIZE 16 |
static char text[] = "Lorem ipsum dolor sit amet, consectetur adipisicing elit"; |
static char *read_root(void) |
char *test_vfs1(bool quiet) |
{ |
TPRINTF("Opening the root directory..."); |
DIR *dirp = opendir("/"); |
if (!dirp) { |
TPRINTF("\n"); |
return "opendir() failed"; |
} else |
TPRINTF("OK\n"); |
struct dirent *dp; |
while ((dp = readdir(dirp))) |
TPRINTF(" node \"%s\"\n", dp->d_name); |
closedir(dirp); |
return NULL; |
} |
int rc; |
char *test_vfs1(void) |
{ |
if (mkdir(MOUNT_POINT, 0) != 0) |
return "mkdir() failed"; |
TPRINTF("Created directory %s\n", MOUNT_POINT); |
char null[MAX_DEVICE_NAME]; |
int null_id = devmap_null_create(); |
if (null_id == -1) |
return "Unable to create null device"; |
snprintf(null, MAX_DEVICE_NAME, "null%d", null_id); |
int rc = mount(FS_TYPE, MOUNT_POINT, null, OPTIONS, FLAGS); |
rc = mount("tmpfs", "/", "nulldev0", "", 0); |
switch (rc) { |
case EOK: |
TPRINTF("Mounted /dev/%s as %s on %s\n", null, FS_TYPE, MOUNT_POINT); |
if (!quiet) |
printf("mounted tmpfs on /\n"); |
break; |
case EBUSY: |
TPRINTF("(INFO) Filesystem already mounted on %s\n", MOUNT_POINT); |
if (!quiet) |
printf("(INFO) something is already mounted on /\n"); |
break; |
default: |
TPRINTF("(ERR) IPC returned errno %d (is tmpfs loaded?)\n", rc); |
return "mount() failed"; |
if (!quiet) |
printf("(INFO) IPC returned errno %d\n", rc); |
return "mount() failed."; |
} |
if (mkdir("/mydir", 0) != 0) |
return "mkdir() failed.\n"; |
if (!quiet) |
printf("created directory /mydir\n"); |
if (mkdir(TEST_DIRECTORY, 0) != 0) |
return "mkdir() failed"; |
TPRINTF("Created directory %s\n", TEST_DIRECTORY); |
int fd0 = open(TEST_FILE, O_CREAT); |
int fd0 = open("/mydir/myfile", O_CREAT); |
if (fd0 < 0) |
return "open() failed"; |
TPRINTF("Created file %s (fd=%d)\n", TEST_FILE, fd0); |
return "open() failed.\n"; |
if (!quiet) |
printf("created file /mydir/myfile, fd=%d\n", fd0); |
ssize_t cnt; |
size_t size = sizeof(text); |
ssize_t cnt = write(fd0, text, size); |
cnt = write(fd0, text, size); |
if (cnt < 0) |
return "write() failed"; |
TPRINTF("Written %d bytes\n", cnt); |
return "write() failed.\n"; |
if (!quiet) |
printf("written %d bytes, fd=%d\n", cnt, fd0); |
if (lseek(fd0, 0, SEEK_SET) != 0) |
return "lseek() failed"; |
TPRINTF("Sought to position 0\n"); |
char buf[BUF_SIZE]; |
while ((cnt = read(fd0, buf, BUF_SIZE))) { |
return "lseek() failed.\n"; |
if (!quiet) |
printf("sought to position 0, fd=%d\n", fd0); |
char buf[10]; |
while ((cnt = read(fd0, buf, sizeof(buf)))) { |
if (cnt < 0) |
return "read() failed"; |
TPRINTF("Read %d bytes: \".*s\"\n", cnt, cnt, buf); |
return "read() failed.\n"; |
if (!quiet) |
printf("read %d bytes: \"%.*s\", fd=%d\n", cnt, cnt, |
buf, fd0); |
} |
close(fd0); |
DIR *dirp; |
struct dirent *dp; |
if (!quiet) |
printf("scanning the root directory...\n"); |
dirp = opendir("/"); |
if (!dirp) |
return "opendir() failed\n"; |
while ((dp = readdir(dirp))) |
printf("discovered node %s in /\n", dp->d_name); |
closedir(dirp); |
if (rename("/mydir/myfile", "/mydir/yourfile")) |
return "rename() failed.\n"; |
if (!quiet) |
printf("renamed /mydir/myfile to /mydir/yourfile\n"); |
if (unlink("/mydir/yourfile")) |
return "unlink() failed.\n"; |
char *rv = read_root(); |
if (rv != NULL) |
return rv; |
if (!quiet) |
printf("unlinked file /mydir/yourfile\n"); |
if (rmdir("/mydir")) |
return "rmdir() failed.\n"; |
if (!quiet) |
printf("removed directory /mydir\n"); |
if (rename(TEST_FILE, TEST_FILE2)) |
return "rename() failed"; |
TPRINTF("Renamed %s to %s\n", TEST_FILE, TEST_FILE2); |
if (unlink(TEST_FILE2)) |
return "unlink() failed"; |
TPRINTF("Unlinked %s\n", TEST_FILE2); |
if (rmdir(TEST_DIRECTORY)) |
return "rmdir() failed"; |
TPRINTF("Removed directory %s\n", TEST_DIRECTORY); |
rv = read_root(); |
if (rv != NULL) |
return rv; |
if (!quiet) |
printf("scanning the root directory...\n"); |
dirp = opendir("/"); |
if (!dirp) |
return "opendir() failed\n"; |
while ((dp = readdir(dirp))) |
printf("discovered node %s in /\n", dp->d_name); |
closedir(dirp); |
return NULL; |
} |
/branches/dd/uspace/app/tester/print/print2.def |
---|
File deleted |
/branches/dd/uspace/app/tester/print/print3.def |
---|
File deleted |
/branches/dd/uspace/app/tester/print/print2.c |
---|
File deleted |
/branches/dd/uspace/app/tester/print/print3.c |
---|
File deleted |
/branches/dd/uspace/app/tester/print/print4.c |
---|
30,54 → 30,63 |
#include <unistd.h> |
#include "../tester.h" |
char *test_print4(void) |
#define PRIx8 "x" |
char *test_print4(bool quiet) |
{ |
TPRINTF("ASCII printable characters (32 - 127) using printf(\"%%c\") and printf(\"%%lc\"):\n"); |
uint8_t group; |
for (group = 1; group < 4; group++) { |
TPRINTF("%#x: ", group << 5); |
if (!quiet) { |
printf("ASCII printable characters (32 - 127) using printf(\"%%c\") and printf(\"%%lc\"):\n"); |
uint8_t index; |
for (index = 0; index < 32; index++) |
TPRINTF("%c", (char) ((group << 5) + index)); |
uint8_t group; |
for (group = 1; group < 4; group++) { |
printf("%#" PRIx8 ": ", group << 5); |
uint8_t index; |
for (index = 0; index < 32; index++) |
printf("%c", (char) ((group << 5) + index)); |
printf(" "); |
for (index = 0; index < 32; index++) |
printf("%lc", (wchar_t) ((group << 5) + index)); |
printf("\n"); |
} |
TPRINTF(" "); |
for (index = 0; index < 32; index++) |
TPRINTF("%lc", (wchar_t) ((group << 5) + index)); |
printf("\nExtended ASCII characters (128 - 255) using printf(\"%%lc\"):\n"); |
TPRINTF("\n"); |
} |
TPRINTF("\nExtended ASCII characters (128 - 255) using printf(\"%%lc\"):\n"); |
for (group = 4; group < 8; group++) { |
TPRINTF("%#x: ", group << 5); |
for (group = 4; group < 8; group++) { |
printf("%#" PRIx8 ": ", group << 5); |
uint8_t index; |
for (index = 0; index < 32; index++) |
printf("%lc", (wchar_t) ((group << 5) + index)); |
printf("\n"); |
} |
uint8_t index; |
for (index = 0; index < 32; index++) |
TPRINTF("%lc", (wchar_t) ((group << 5) + index)); |
printf("\nUTF-8 strings using printf(\"%%s\"):\n"); |
printf("English: %s\n", "Quick brown fox jumps over the lazy dog"); |
printf("Czech: %s\n", "Příliš žluťoučký kůň úpěl ďábelské ódy"); |
printf("Greek: %s\n", "á½® ξεῖν’, ἀγγÎλλειν Λακεδαιμονίοις ὅτι τῇδε"); |
printf("Hebrew: %s\n", "משוואת ברנולי היא משוואה בהידרודינמיקה"); |
printf("Arabic: %s\n", "التوزيع الجغرافي للحمل العنقودي"); |
printf("Russian: %s\n", "Леннон познакомился с художницей-авангардисткой"); |
printf("Armenian: %s\n", "ÕÕ¯Õ½Õ¥Ö Õ°Ö€Õ¡Õ¿Õ¡Ö€Õ¡Õ¯Õ¾Õ¥Õ¬ ÔµÖ€Õ¸Ö‚Õ½Õ¡Õ²Õ¥Õ´Õ« Õ°Õ¡ÕµÕ¯Õ¡Õ¯Õ¡Õ¶"); |
TPRINTF("\n"); |
printf("\nUTF-32 strings using printf(\"%%ls\"):\n"); |
printf("English: %ls\n", L"Quick brown fox jumps over the lazy dog"); |
printf("Czech: %ls\n", L"Příliš žluťoučký kůň úpěl ďábelské ódy"); |
printf("Greek: %ls\n", L"á½® ξεῖν’, ἀγγÎλλειν Λακεδαιμονίοις ὅτι τῇδε"); |
printf("Hebrew: %ls\n", L"משוואת ברנולי היא משוואה בהידרודינמיקה"); |
printf("Arabic: %ls\n", L"التوزيع الجغرافي للحمل العنقودي"); |
printf("Russian: %ls\n", L"Леннон познакомился с художницей-авангардисткой"); |
printf("Armenian: %ls\n", L"ÕÕ¯Õ½Õ¥Ö Õ°Ö€Õ¡Õ¿Õ¡Ö€Õ¡Õ¯Õ¾Õ¥Õ¬ ÔµÖ€Õ¸Ö‚Õ½Õ¡Õ²Õ¥Õ´Õ« Õ°Õ¡ÕµÕ¯Õ¡Õ¯Õ¡Õ¶"); |
printf("Test: [%d] '%lc'\n", L'\x0161', L'\x0161'); |
} |
printf("[Press a key]\n"); |
getchar(); |
TPRINTF("\nUTF-8 strings using printf(\"%%s\"):\n"); |
TPRINTF("English: %s\n", "Quick brown fox jumps over the lazy dog"); |
TPRINTF("Czech: %s\n", "Příliš žluťoučký kůň úpěl ďábelské ódy"); |
TPRINTF("Greek: %s\n", "á½® ξεῖν’, ἀγγÎλλειν Λακεδαιμονίοις ὅτι τῇδε"); |
TPRINTF("Hebrew: %s\n", "משוואת ברנולי היא משוואה בהידרודינמיקה"); |
TPRINTF("Arabic: %s\n", "التوزيع الجغرافي للحمل العنقودي"); |
TPRINTF("Russian: %s\n", "Леннон познакомился с художницей-авангардисткой"); |
TPRINTF("Armenian: %s\n", "ÕÕ¯Õ½Õ¥Ö Õ°Ö€Õ¡Õ¿Õ¡Ö€Õ¡Õ¯Õ¾Õ¥Õ¬ ÔµÖ€Õ¸Ö‚Õ½Õ¡Õ²Õ¥Õ´Õ« Õ°Õ¡ÕµÕ¯Õ¡Õ¯Õ¡Õ¶"); |
TPRINTF("\nUTF-32 strings using printf(\"%%ls\"):\n"); |
TPRINTF("English: %ls\n", L"Quick brown fox jumps over the lazy dog"); |
TPRINTF("Czech: %ls\n", L"Příliš žluťoučký kůň úpěl ďábelské ódy"); |
TPRINTF("Greek: %ls\n", L"á½® ξεῖν’, ἀγγÎλλειν Λακεδαιμονίοις ὅτι τῇδε"); |
TPRINTF("Hebrew: %ls\n", L"משוואת ברנולי היא משוואה בהידרודינמיקה"); |
TPRINTF("Arabic: %ls\n", L"التوزيع الجغرافي للحمل العنقودي"); |
TPRINTF("Russian: %ls\n", L"Леннон познакомился с художницей-авангардисткой"); |
TPRINTF("Armenian: %ls\n", L"ÕÕ¯Õ½Õ¥Ö Õ°Ö€Õ¡Õ¿Õ¡Ö€Õ¡Õ¯Õ¾Õ¥Õ¬ ÔµÖ€Õ¸Ö‚Õ½Õ¡Õ²Õ¥Õ´Õ« Õ°Õ¡ÕµÕ¯Õ¡Õ¯Õ¡Õ¶"); |
return NULL; |
} |
/branches/dd/uspace/app/tester/print/print1.def |
---|
1,6 → 1,6 |
{ |
"print1", |
"String printf test", |
"Printf test", |
&test_print1, |
true |
}, |
/branches/dd/uspace/app/tester/print/print1.c |
---|
30,27 → 30,44 |
#include <unistd.h> |
#include "../tester.h" |
char *test_print1(void) |
#define BUFFER_SIZE 32 |
char * test_print1(bool quiet) |
{ |
TPRINTF("Testing printf(\"%%*.*s\", 5, 3, \"text\"):\n"); |
TPRINTF("Expected output: \" tex\"\n"); |
TPRINTF("Real output: \"%*.*s\"\n\n", 5, 3, "text"); |
if (!quiet) { |
int retval; |
unsigned int nat = 0x12345678u; |
char buffer[BUFFER_SIZE]; |
printf(" text 10.8s %*.*s \n", 5, 3, "text"); |
printf(" very long text 10.8s %10.8s \n", "very long text"); |
printf(" text 8.10s %8.10s \n", "text"); |
printf(" very long text 8.10s %8.10s \n", "very long text"); |
printf(" char: c '%c', 3.2c '%3.2c', -3.2c '%-3.2c', 2.3c '%2.3c', -2.3c '%-2.3c' \n",'a', 'b', 'c', 'd', 'e' ); |
printf(" int: d '%d', 3.2d '%3.2d', -3.2d '%-3.2d', 2.3d '%2.3d', -2.3d '%-2.3d' \n",1, 1, 1, 1, 1 ); |
printf(" -int: d '%d', 3.2d '%3.2d', -3.2d '%-3.2d', 2.3d '%2.3d', -2.3d '%-2.3d' \n",-1, -1, -1, -1, -1 ); |
printf(" 0xint: x '%#x', 5.3x '%#5.3x', -5.3x '%#-5.3x', 3.5x '%#3.5x', -3.5x '%#-3.5x' \n",17, 17, 17, 17, 17 ); |
printf("'%#llx' 64bit, '%#x' 32bit, '%#hhx' 8bit, '%#hx' 16bit, unative_t '%#zx'. '%#llx' 64bit and '%s' string.\n", 0x1234567887654321ll, 0x12345678, 0x12, 0x1234, nat, 0x1234567887654321ull, "Lovely string" ); |
printf(" Print to NULL '%s'\n", NULL); |
retval = snprintf(buffer, BUFFER_SIZE, "Short text without parameters."); |
printf("Result is: '%s', retval = %d\n", buffer, retval); |
retval = snprintf(buffer, BUFFER_SIZE, "Very very very long text without parameters."); |
printf("Result is: '%s', retval = %d\n", buffer, retval); |
printf("Print short text to %d char long buffer via snprintf.\n", BUFFER_SIZE); |
retval = snprintf(buffer, BUFFER_SIZE, "Short %s", "text"); |
printf("Result is: '%s', retval = %d\n", buffer, retval); |
printf("Print long text to %d char long buffer via snprintf.\n", BUFFER_SIZE); |
retval = snprintf(buffer, BUFFER_SIZE, "Very long %s. This text`s length is more than %d. We are interested in the result.", "text" , BUFFER_SIZE); |
printf("Result is: '%s', retval = %d\n", buffer, retval); |
} |
TPRINTF("Testing printf(\"%%10.8s\", \"very long text\"):\n"); |
TPRINTF("Expected output: \" very lon\"\n"); |
TPRINTF("Real output: \"%10.8s\"\n\n", "very long text"); |
TPRINTF("Testing printf(\"%%8.10s\", \"text\"):\n"); |
TPRINTF("Expected output: \"text\"\n"); |
TPRINTF("Real output: \"%8.10s\"\n\n", "text"); |
TPRINTF("Testing printf(\"%%8.10s\", \"very long text\"):\n"); |
TPRINTF("Expected output: \"very long \"\n"); |
TPRINTF("Real output: \"%8.10s\"\n\n", "very long text"); |
TPRINTF("Testing printf(\"%%s\", NULL):\n"); |
TPRINTF("Expected output: \"(NULL)\"\n"); |
TPRINTF("Real output: \"%s\"\n\n", NULL); |
return NULL; |
} |
/branches/dd/uspace/app/tester/stdio/stdio2.c |
---|
31,53 → 31,39 |
#include <errno.h> |
#include "../tester.h" |
char *test_stdio2(void) |
char * test_stdio2(bool quiet) |
{ |
FILE *file; |
FILE *f; |
char *file_name = "/test"; |
TPRINTF("Open file \"%s\" for writing...", file_name); |
size_t n; |
int c; |
printf("Open file '%s' for writing\n", file_name); |
errno = 0; |
file = fopen(file_name, "wt"); |
if (file == NULL) { |
TPRINTF("errno = %d\n", errno); |
return "Failed opening file"; |
} else |
TPRINTF("OK\n"); |
TPRINTF("Write to file..."); |
fprintf(file, "integer: %u, string: \"%s\"", 42, "Hello!"); |
TPRINTF("OK\n"); |
TPRINTF("Close..."); |
if (fclose(file) != 0) { |
TPRINTF("errno = %d\n", errno); |
return "Failed closing file"; |
} else |
TPRINTF("OK\n"); |
TPRINTF("Open file \"%s\" for reading...", file_name); |
file = fopen(file_name, "rt"); |
if (file == NULL) { |
TPRINTF("errno = %d\n", errno); |
return "Failed opening file"; |
} else |
TPRINTF("OK\n"); |
TPRINTF("File contains:\n"); |
f = fopen(file_name, "wt"); |
if (f == NULL) |
return "Failed opening file."; |
fprintf(f, "Integer: %d, string: '%s'\n", 42, "Hello!"); |
if (fclose(f) != 0) |
return "Failed closing file."; |
printf("Open file '%s' for reading\n", file_name); |
f = fopen(file_name, "rt"); |
if (f == NULL) |
return "Failed opening file."; |
printf("File contains:\n"); |
while (true) { |
int c = fgetc(file); |
if (c == EOF) |
break; |
TPRINTF("%c", c); |
c = fgetc(f); |
if (c == EOF) break; |
putchar(c); |
} |
TPRINTF("\nClose..."); |
if (fclose(file) != 0) { |
TPRINTF("errno = %d\n", errno); |
return "Failed closing file"; |
} else |
TPRINTF("OK\n"); |
if (fclose(f) != 0) |
return "Failed closing file."; |
return NULL; |
} |
/branches/dd/uspace/app/tester/stdio/stdio1.c |
---|
31,60 → 31,55 |
#include <errno.h> |
#include "../tester.h" |
#define BUF_SIZE 32 |
#define BUF_SIZE 32 |
static char buf[BUF_SIZE + 1]; |
char *test_stdio1(void) |
char * test_stdio1(bool quiet) |
{ |
FILE *file; |
FILE *f; |
char *file_name = "/readme"; |
TPRINTF("Open file \"%s\"...", file_name); |
size_t n; |
int c; |
printf("Open file '%s'\n", file_name); |
errno = 0; |
file = fopen(file_name, "rt"); |
if (file == NULL) { |
TPRINTF("errno = %d\n", errno); |
return "Failed opening file"; |
} else |
TPRINTF("OK\n"); |
TPRINTF("Read file..."); |
size_t cnt = fread(buf, 1, BUF_SIZE, file); |
if (ferror(file)) { |
TPRINTF("errno = %d\n", errno); |
fclose(file); |
return "Failed reading file"; |
} else |
TPRINTF("OK\n"); |
buf[cnt] = '\0'; |
TPRINTF("Read %u bytes, string \"%s\"\n", cnt, buf); |
TPRINTF("Seek to beginning..."); |
if (fseek(file, 0, SEEK_SET) != 0) { |
TPRINTF("errno = %d\n", errno); |
fclose(file); |
return "Failed seeking in file"; |
} else |
TPRINTF("OK\n"); |
TPRINTF("Read using fgetc()..."); |
f = fopen(file_name, "rt"); |
if (f == NULL) printf("errno = %d\n", errno); |
if (f == NULL) |
return "Failed opening file."; |
n = fread(buf, 1, BUF_SIZE, f); |
if (ferror(f)) { |
fclose(f); |
return "Failed reading file."; |
} |
printf("Read %d bytes.\n", n); |
buf[n] = '\0'; |
printf("Read string '%s'.\n", buf); |
printf("Seek to beginning.\n"); |
if (fseek(f, 0, SEEK_SET) != 0) { |
fclose(f); |
return "Failed seeking."; |
} |
printf("Read using fgetc().\n"); |
while (true) { |
int c = fgetc(file); |
if (c == EOF) |
break; |
TPRINTF("."); |
c = fgetc(f); |
if (c == EOF) break; |
printf("'%c'", c); |
} |
TPRINTF("[EOF]\n"); |
TPRINTF("Close..."); |
if (fclose(file) != 0) { |
TPRINTF("errno = %d\n", errno); |
return "Failed closing file"; |
} else |
TPRINTF("OK\n"); |
printf("[EOF]\n"); |
printf("Closing.\n"); |
if (fclose(f) != 0) |
return "Failed closing."; |
return NULL; |
} |
/branches/dd/uspace/app/tester/loop/loop1.c |
---|
30,11 → 30,12 |
#include <stdlib.h> |
#include "../tester.h" |
char *test_loop1(void) |
char *test_loop1(bool quiet) |
{ |
TPRINTF("Looping..."); |
while (true); |
TPRINTF("\n"); |
return "Survived endless loop"; |
printf("Looping...\n"); |
while (1); |
printf("Survived endless loop?!!\n"); |
return NULL; |
} |
/branches/dd/uspace/app/tester/thread/thread1.c |
---|
27,8 → 27,7 |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
#define THREADS 20 |
#define DELAY 10 |
#define THREADS 5 |
#include <atomic.h> |
#include <thread.h> |
43,38 → 42,40 |
static void threadtest(void *data) |
{ |
thread_detach(thread_get_id()); |
while (atomic_get(&finish)) |
while (atomic_get(&finish)) { |
if (!sh_quiet) |
printf("%llu ", thread_get_id()); |
usleep(100000); |
} |
atomic_inc(&threads_finished); |
} |
char *test_thread1(void) |
char * test_thread1(bool quiet) |
{ |
unsigned int i; |
unsigned int total = 0; |
unsigned int i, total = 0; |
sh_quiet = quiet; |
atomic_set(&finish, 1); |
atomic_set(&threads_finished, 0); |
TPRINTF("Creating threads"); |
for (i = 0; i < THREADS; i++) { |
for (i = 0; i < THREADS; i++) { |
if (thread_create(threadtest, NULL, "threadtest", NULL) < 0) { |
TPRINTF("\nCould not create thread %u\n", i); |
if (!quiet) |
printf("Could not create thread %d\n", i); |
break; |
} |
TPRINTF("."); |
total++; |
} |
TPRINTF("\nRunning threads for %u seconds...", DELAY); |
sleep(DELAY); |
TPRINTF("\n"); |
if (!quiet) |
printf("Running threads for 10 seconds...\n"); |
sleep(10); |
atomic_set(&finish, 0); |
while (atomic_get(&threads_finished) < total) { |
TPRINTF("Threads left: %u\n", total - atomic_get(&threads_finished)); |
if (!quiet) |
printf("Threads left: %d\n", total - atomic_get(&threads_finished)); |
sleep(1); |
} |
/branches/dd/uspace/app/tester/fault/fault1.c |
---|
29,7 → 29,7 |
#include "../tester.h" |
char *test_fault1(void) |
char * test_fault1(bool quiet) |
{ |
((int *)(0))[1] = 0; |
/branches/dd/uspace/app/tester/fault/fault2.c |
---|
29,7 → 29,7 |
#include "../tester.h" |
char *test_fault2(void) |
char * test_fault2(bool quiet) |
{ |
volatile long long var; |
volatile int var1; |
/branches/dd/uspace/app/getvc/getvc.c |
---|
73,9 → 73,6 |
int main(int argc, char *argv[]) |
{ |
task_exit_t texit; |
int retval; |
if (argc < 3) { |
usage(); |
return -1; |
86,12 → 83,6 |
stdin = fopen(argv[1], "r"); |
stdout = fopen(argv[1], "w"); |
stderr = fopen(argv[1], "w"); |
/* |
* FIXME: fopen() should actually detect that we are opening a console |
* and it should set line-buffering mode automatically. |
*/ |
setvbuf(stdout, NULL, _IOLBF, BUFSIZ); |
if ((stdin == NULL) |
|| (stdout == NULL) |
100,7 → 91,7 |
version_print(argv[1]); |
task_id_t id = spawn(argv[2]); |
task_wait(id, &texit, &retval); |
task_wait(id); |
return 0; |
} |
/branches/dd/uspace/app/tetris/scores.c |
---|
196,38 → 196,5 |
} |
} |
int loadscores(void) |
{ |
FILE *f; |
size_t cnt; |
int rc; |
f = fopen("/data/tetris.sco", "rb"); |
if (f == NULL) |
return ENOENT; |
cnt = fread(scores, sizeof(struct highscore), NUMSPOTS, f); |
rc = fclose(f); |
if (cnt != NUMSPOTS || rc != 0) |
return EIO; |
return EOK; |
} |
void savescores(void) |
{ |
FILE *f; |
size_t cnt; |
int rc; |
f = fopen("/data/tetris.sco", "wb"); |
cnt = fwrite(scores, sizeof(struct highscore), NUMSPOTS, f); |
rc = fclose(f); |
if (cnt != NUMSPOTS || rc != 0) |
printf("Error saving score table\n"); |
} |
/** @} |
*/ |
/branches/dd/uspace/app/tetris/screen.c |
---|
62,8 → 62,6 |
static int curscore; |
static int isset; /* true => terminal is in game mode */ |
static int use_color; /* true => use colors */ |
static const struct shape *lastshape; |
79,14 → 77,11 |
static void start_standout(uint32_t color) |
{ |
fflush(stdout); |
console_set_rgb_color(fphone(stdout), 0xf0f0f0, |
use_color ? color : 0x000000); |
console_set_rgb_color(fphone(stdout), 0xf0f0f0, color); |
} |
static void resume_normal(void) |
{ |
fflush(stdout); |
console_set_rgb_color(fphone(stdout), 0, 0xf0f0f0); |
} |
119,7 → 114,6 |
void moveto(int r, int c) |
{ |
fflush(stdout); |
console_goto(fphone(stdout), c, r); |
} |
130,18 → 124,6 |
return console_get_size(fphone(stdout), &ws->ws_col, &ws->ws_row); |
} |
static int get_display_color_sup(void) |
{ |
int rc; |
int ccap; |
rc = console_get_color_cap(fphone(stdout), &ccap); |
if (rc != 0) |
return 0; |
return (ccap >= CONSOLE_CCAP_RGB); |
} |
/* |
* Set up screen mode. |
*/ |
156,8 → 138,6 |
Rows = ws.ws_row; |
Cols = ws.ws_col; |
} |
use_color = get_display_color_sup(); |
if ((Rows < MINROWS) || (Cols < MINCOLS)) { |
char smallscr[55]; |
/branches/dd/uspace/app/tetris/scores.h |
---|
64,8 → 64,6 |
extern void showscores(int); |
extern void initscores(void); |
extern void insertscore(int score, int level); |
extern int loadscores(void); |
extern void savescores(void); |
/** @} |
*/ |
/branches/dd/uspace/app/tetris/tetris.c |
---|
49,7 → 49,6 |
#include <sys/time.h> |
#include <sys/types.h> |
#include <err.h> |
#include <errno.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
207,7 → 206,6 |
printf("off"); |
break; |
case 'h': |
loadscores(); |
showscores(firstgame); |
tetris_menu_draw(*level); |
break; |
299,9 → 297,7 |
key_write[4], key_write[5]); |
scr_init(); |
if (loadscores() != EOK) |
initscores(); |
initscores(); |
while (tetris_menu(&level)) { |
fallrate = 1000000 / level; |
419,9 → 415,7 |
} |
scr_clear(); |
loadscores(); |
insertscore(score, level); |
savescores(); |
score = 0; |
} |
/branches/dd/uspace/app/trace/trace.c |
---|
43,11 → 43,7 |
#include <task.h> |
#include <mem.h> |
#include <string.h> |
#include <bool.h> |
#include <loader/loader.h> |
#include <io/console.h> |
#include <io/keycode.h> |
#include <fibril_sync.h> |
#include <libc.h> |
68,31 → 64,22 |
int next_thread_id; |
ipc_call_t thread_ipc_req[THBUF_SIZE]; |
int phoneid; |
bool abort_trace; |
int abort_trace; |
uintptr_t thash; |
static bool paused; |
static fibril_condvar_t state_cv; |
static fibril_mutex_t state_lock; |
volatile int paused; |
static bool cev_valid; |
static console_event_t cev; |
void thread_trace_start(uintptr_t thread_hash); |
static proto_t *proto_console; |
static task_id_t task_id; |
static loader_t *task_ldr; |
static bool task_wait_for; |
/** Combination of events/data to print. */ |
display_mask_t display_mask; |
static int program_run_fibril(void *arg); |
static int cev_fibril(void *arg); |
static void program_run(void) |
{ |
107,19 → 94,6 |
fibril_add_ready(fid); |
} |
static void cev_fibril_start(void) |
{ |
fid_t fid; |
fid = fibril_create(cev_fibril, NULL); |
if (fid == 0) { |
printf("Error creating fibril\n"); |
exit(1); |
} |
fibril_add_ready(fid); |
} |
static int program_run_fibril(void *arg) |
{ |
int rc; |
341,7 → 315,7 |
ipcp_call_sync(phoneidx, &question, &reply); |
} |
static void sc_ipc_call_sync_slow_b(unsigned thread_id, sysarg_t *sc_args) |
static void sc_ipc_call_sync_slow(sysarg_t *sc_args) |
{ |
ipc_call_t question, reply; |
int rc; |
348,27 → 322,15 |
memset(&question, 0, sizeof(question)); |
rc = udebug_mem_read(phoneid, &question.args, sc_args[1], sizeof(question.args)); |
if (rc < 0) { |
printf("Error: mem_read->%d\n", rc); |
return; |
} |
printf("dmr->%d\n", rc); |
if (rc < 0) return; |
thread_ipc_req[thread_id] = question; |
} |
static void sc_ipc_call_sync_slow_e(unsigned thread_id, sysarg_t *sc_args) |
{ |
ipc_call_t question, reply; |
int rc; |
memset(&reply, 0, sizeof(reply)); |
rc = udebug_mem_read(phoneid, &reply.args, sc_args[2], sizeof(reply.args)); |
if (rc < 0) { |
printf("Error: mem_read->%d\n", rc); |
return; |
} |
printf("dmr->%d\n", rc); |
if (rc < 0) return; |
ipcp_call_sync(sc_args[0], &thread_ipc_req[thread_id], &reply); |
ipcp_call_sync(sc_args[0], &question, &reply); |
} |
static void sc_ipc_wait(sysarg_t *sc_args, int sc_rc) |
413,14 → 375,6 |
print_sc_args(sc_args, syscall_desc[sc_id].n_args); |
} |
switch (sc_id) { |
case SYS_IPC_CALL_SYNC_SLOW: |
sc_ipc_call_sync_slow_b(thread_id, sc_args); |
break; |
default: |
break; |
} |
async_serialize_end(); |
} |
461,7 → 415,7 |
sc_ipc_call_sync_fast(sc_args); |
break; |
case SYS_IPC_CALL_SYNC_SLOW: |
sc_ipc_call_sync_slow_e(thread_id, sc_args); |
sc_ipc_call_sync_slow(sc_args); |
break; |
case SYS_IPC_WAIT: |
sc_ipc_wait(sc_args, sc_rc); |
492,26 → 446,20 |
thread_hash = (uintptr_t)thread_hash_arg; |
thread_id = next_thread_id++; |
if (thread_id >= THBUF_SIZE) { |
printf("Too many threads.\n"); |
return ELIMIT; |
} |
printf("Start tracing thread [%d] (hash 0x%lx).\n", thread_id, thread_hash); |
while (!abort_trace) { |
fibril_mutex_lock(&state_lock); |
if (paused) { |
printf("Thread [%d] paused. Press R to resume.\n", |
thread_id); |
while (paused) |
fibril_condvar_wait(&state_cv, &state_lock); |
printf("Thread [%d] resumed.\n", thread_id); |
printf("Press R to resume (and be patient).\n"); |
while (paused) { |
usleep(1000000); |
fibril_yield(); |
printf("."); |
} |
printf("Resumed\n"); |
} |
fibril_mutex_unlock(&state_lock); |
/* Run thread until an event occurs */ |
rc = udebug_go(phoneid, thread_hash, |
533,9 → 481,6 |
break; |
case UDEBUG_EVENT_STOP: |
printf("Stop event\n"); |
fibril_mutex_lock(&state_lock); |
paused = true; |
fibril_mutex_unlock(&state_lock); |
break; |
case UDEBUG_EVENT_THREAD_B: |
event_thread_b(val0); |
542,10 → 487,7 |
break; |
case UDEBUG_EVENT_THREAD_E: |
printf("Thread 0x%lx exited.\n", val0); |
fibril_mutex_lock(&state_lock); |
abort_trace = true; |
fibril_condvar_broadcast(&state_cv); |
fibril_mutex_unlock(&state_lock); |
abort_trace = 1; |
break; |
default: |
printf("Unknown event type %d.\n", ev_type); |
598,33 → 540,6 |
if (rc != EOK) |
goto error; |
/* Send default files */ |
fdi_node_t *files[4]; |
fdi_node_t stdin_node; |
fdi_node_t stdout_node; |
fdi_node_t stderr_node; |
if ((stdin != NULL) && (fnode(stdin, &stdin_node) == EOK)) |
files[0] = &stdin_node; |
else |
files[0] = NULL; |
if ((stdout != NULL) && (fnode(stdout, &stdout_node) == EOK)) |
files[1] = &stdout_node; |
else |
files[1] = NULL; |
if ((stderr != NULL) && (fnode(stderr, &stderr_node) == EOK)) |
files[2] = &stderr_node; |
else |
files[2] = NULL; |
files[3] = NULL; |
rc = loader_set_files(ldr, files); |
if (rc != EOK) |
goto error; |
/* Load the program. */ |
rc = loader_load_program(ldr); |
if (rc != EOK) |
640,32 → 555,11 |
return NULL; |
} |
static int cev_fibril(void *arg) |
{ |
(void) arg; |
while (true) { |
fibril_mutex_lock(&state_lock); |
while (cev_valid) |
fibril_condvar_wait(&state_cv, &state_lock); |
fibril_mutex_unlock(&state_lock); |
if (!console_get_event(fphone(stdin), &cev)) |
return -1; |
fibril_mutex_lock(&state_lock); |
cev_valid = true; |
fibril_condvar_broadcast(&state_cv); |
fibril_mutex_unlock(&state_lock); |
} |
} |
static void trace_task(task_id_t task_id) |
{ |
console_event_t ev; |
bool done; |
int i; |
int rc; |
int c; |
ipcp_init(); |
681,55 → 575,29 |
return; |
} |
abort_trace = false; |
abort_trace = 0; |
for (i = 0; i < n_threads; i++) { |
thread_trace_start(thread_hash_buf[i]); |
} |
done = false; |
while (!done) { |
fibril_mutex_lock(&state_lock); |
while (!cev_valid && !abort_trace) |
fibril_condvar_wait(&state_cv, &state_lock); |
fibril_mutex_unlock(&state_lock); |
ev = cev; |
fibril_mutex_lock(&state_lock); |
cev_valid = false; |
fibril_condvar_broadcast(&state_cv); |
fibril_mutex_unlock(&state_lock); |
if (abort_trace) |
break; |
if (ev.type != KEY_PRESS) |
continue; |
switch (ev.key) { |
case KC_Q: |
done = true; |
break; |
case KC_P: |
while(1) { |
c = getchar(); |
if (c == 'q') break; |
if (c == 'p') { |
printf("Pause...\n"); |
paused = 1; |
rc = udebug_stop(phoneid, thash); |
if (rc != EOK) |
printf("Error: stop -> %d\n", rc); |
break; |
case KC_R: |
fibril_mutex_lock(&state_lock); |
paused = false; |
fibril_condvar_broadcast(&state_cv); |
fibril_mutex_unlock(&state_lock); |
printf("stop -> %d\n", rc); |
} |
if (c == 'r') { |
paused = 0; |
printf("Resume...\n"); |
break; |
} |
} |
printf("\nTerminate debugging session...\n"); |
abort_trace = true; |
abort_trace = 1; |
udebug_end(phoneid); |
ipc_hangup(phoneid); |
761,53 → 629,37 |
}; |
next_thread_id = 1; |
paused = false; |
cev_valid = false; |
paused = 0; |
fibril_mutex_initialize(&state_lock); |
fibril_condvar_initialize(&state_cv); |
proto_init(); |
p = proto_new("vfs"); |
o = oper_new("open", 2, arg_def, V_INT_ERRNO, 0, resp_def); |
proto_add_oper(p, VFS_IN_OPEN, o); |
o = oper_new("open_node", 4, arg_def, V_INT_ERRNO, 0, resp_def); |
proto_add_oper(p, VFS_IN_OPEN_NODE, o); |
o = oper_new("read", 1, arg_def, V_ERRNO, 1, resp_def); |
proto_add_oper(p, VFS_IN_READ, o); |
proto_add_oper(p, VFS_READ, o); |
o = oper_new("write", 1, arg_def, V_ERRNO, 1, resp_def); |
proto_add_oper(p, VFS_IN_WRITE, o); |
o = oper_new("seek", 3, arg_def, V_ERRNO, 0, resp_def); |
proto_add_oper(p, VFS_IN_SEEK, o); |
proto_add_oper(p, VFS_WRITE, o); |
o = oper_new("truncate", 5, arg_def, V_ERRNO, 0, resp_def); |
proto_add_oper(p, VFS_IN_TRUNCATE, o); |
o = oper_new("fstat", 1, arg_def, V_ERRNO, 0, resp_def); |
proto_add_oper(p, VFS_IN_FSTAT, o); |
o = oper_new("close", 1, arg_def, V_ERRNO, 0, resp_def); |
proto_add_oper(p, VFS_IN_CLOSE, o); |
proto_add_oper(p, VFS_TRUNCATE, o); |
o = oper_new("mount", 2, arg_def, V_ERRNO, 0, resp_def); |
proto_add_oper(p, VFS_IN_MOUNT, o); |
proto_add_oper(p, VFS_MOUNT, o); |
/* o = oper_new("unmount", 0, arg_def); |
proto_add_oper(p, VFS_IN_UNMOUNT, o);*/ |
o = oper_new("sync", 1, arg_def, V_ERRNO, 0, resp_def); |
proto_add_oper(p, VFS_IN_SYNC, o); |
proto_add_oper(p, VFS_UNMOUNT, o);*/ |
o = oper_new("open", 2, arg_def, V_INT_ERRNO, 0, resp_def); |
proto_add_oper(p, VFS_OPEN, o); |
o = oper_new("close", 1, arg_def, V_ERRNO, 0, resp_def); |
proto_add_oper(p, VFS_CLOSE, o); |
o = oper_new("seek", 3, arg_def, V_ERRNO, 0, resp_def); |
proto_add_oper(p, VFS_SEEK, o); |
o = oper_new("mkdir", 1, arg_def, V_ERRNO, 0, resp_def); |
proto_add_oper(p, VFS_IN_MKDIR, o); |
proto_add_oper(p, VFS_MKDIR, o); |
o = oper_new("unlink", 0, arg_def, V_ERRNO, 0, resp_def); |
proto_add_oper(p, VFS_IN_UNLINK, o); |
proto_add_oper(p, VFS_UNLINK, o); |
o = oper_new("rename", 0, arg_def, V_ERRNO, 0, resp_def); |
proto_add_oper(p, VFS_IN_RENAME, o); |
o = oper_new("stat", 0, arg_def, V_ERRNO, 0, resp_def); |
proto_add_oper(p, VFS_IN_STAT, o); |
proto_add_oper(p, VFS_RENAME, o); |
proto_register(SERVICE_VFS, p); |
p = proto_new("console"); |
o = oper_new("write", 1, arg_def, V_ERRNO, 1, resp_def); |
proto_add_oper(p, VFS_IN_WRITE, o); |
resp_def[0] = V_INTEGER; resp_def[1] = V_INTEGER; |
resp_def[2] = V_INTEGER; resp_def[3] = V_CHAR; |
o = oper_new("getkey", 0, arg_def, V_ERRNO, 4, resp_def); |
900,7 → 752,6 |
--argc; ++argv; |
task_id = strtol(*argv, &err_p, 10); |
task_ldr = NULL; |
task_wait_for = false; |
if (*err_p) { |
printf("Task ID syntax error\n"); |
print_syntax(); |
938,7 → 789,6 |
while (*cp) printf("'%s'\n", *cp++); |
} |
task_ldr = preload_task(*argv, argv, &task_id); |
task_wait_for = true; |
return 0; |
} |
946,8 → 796,6 |
int main(int argc, char *argv[]) |
{ |
int rc; |
task_exit_t texit; |
int retval; |
printf("System Call / IPC Tracer\n"); |
printf("Controls: Q - Quit, P - Pause, R - Resume\n"); |
967,29 → 815,12 |
printf("Connected to task %lld.\n", task_id); |
if (task_ldr != NULL) |
if (task_ldr != NULL) { |
program_run(); |
} |
cev_fibril_start(); |
trace_task(task_id); |
if (task_wait_for) { |
printf("Waiting for task to exit.\n"); |
rc = task_wait(task_id, &texit, &retval); |
if (rc != EOK) { |
printf("Failed waiting for task.\n"); |
return -1; |
} |
if (texit == TASK_EXIT_NORMAL) { |
printf("Task exited normally, return value %d.\n", |
retval); |
} else { |
printf("Task exited unexpectedly.\n"); |
} |
} |
return 0; |
} |
/branches/dd/uspace/lib/libfs/libfs.c |
---|
43,7 → 43,6 |
#include <assert.h> |
#include <dirent.h> |
#include <mem.h> |
#include <sys/stat.h> |
/** Register file system server. |
* |
70,7 → 69,7 |
* out-of-order, when it knows that the operation succeeded or failed. |
*/ |
ipc_call_t answer; |
aid_t req = async_send_0(vfs_phone, VFS_IN_REGISTER, &answer); |
aid_t req = async_send_0(vfs_phone, VFS_REGISTER, &answer); |
/* |
* Send our VFS info structure to VFS. |
105,7 → 104,7 |
} |
/* |
* Pick up the answer for the request to the VFS_IN_REQUEST call. |
* Pick up the answer for the request to the VFS_REQUEST call. |
*/ |
async_wait_for(req, NULL); |
reg->fs_handle = (int) IPC_GET_ARG1(answer); |
187,7 → 186,7 |
} |
ipc_call_t answer; |
aid_t msg = async_send_1(mountee_phone, VFS_OUT_MOUNTED, mr_dev_handle, |
aid_t msg = async_send_1(mountee_phone, VFS_MOUNTED, mr_dev_handle, |
&answer); |
ipc_forward_fast(callid, mountee_phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME); |
async_wait_for(msg, &rc); |
214,8 → 213,8 |
* file system implementation |
* @param fs_handle File system handle of the file system where to perform |
* the lookup. |
* @param rid Request ID of the VFS_OUT_LOOKUP request. |
* @param request VFS_OUT_LOOKUP request data itself. |
* @param rid Request ID of the VFS_LOOKUP request. |
* @param request VFS_LOOKUP request data itself. |
* |
*/ |
void libfs_lookup(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid, |
238,7 → 237,7 |
fs_node_t *tmp = NULL; |
if (cur->mp_data.mp_active) { |
ipc_forward_slow(rid, cur->mp_data.phone, VFS_OUT_LOOKUP, |
ipc_forward_slow(rid, cur->mp_data.phone, VFS_LOOKUP, |
next, last, cur->mp_data.dev_handle, lflag, index, |
IPC_FF_ROUTE_FROM_ME); |
ops->node_put(cur); |
273,9 → 272,9 |
else |
next--; |
ipc_forward_slow(rid, tmp->mp_data.phone, |
VFS_OUT_LOOKUP, next, last, tmp->mp_data.dev_handle, |
lflag, index, IPC_FF_ROUTE_FROM_ME); |
ipc_forward_slow(rid, tmp->mp_data.phone, VFS_LOOKUP, |
next, last, tmp->mp_data.dev_handle, lflag, index, |
IPC_FF_ROUTE_FROM_ME); |
ops->node_put(cur); |
ops->node_put(tmp); |
if (par) |
429,42 → 428,12 |
ops->node_put(tmp); |
} |
void libfs_stat(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid, |
ipc_call_t *request) |
{ |
dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request); |
fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request); |
fs_node_t *fn = ops->node_get(dev_handle, index); |
ipc_callid_t callid; |
size_t size; |
if (!ipc_data_read_receive(&callid, &size) || |
size != sizeof(struct stat)) { |
ipc_answer_0(callid, EINVAL); |
ipc_answer_0(rid, EINVAL); |
return; |
} |
struct stat stat; |
memset(&stat, 0, sizeof(struct stat)); |
stat.fs_handle = fs_handle; |
stat.dev_handle = dev_handle; |
stat.index = index; |
stat.lnkcnt = ops->lnkcnt_get(fn); |
stat.is_file = ops->is_file(fn); |
stat.size = ops->size_get(fn); |
ipc_data_read_finalize(callid, &stat, sizeof(struct stat)); |
ipc_answer_0(rid, EOK); |
} |
/** Open VFS triplet. |
* |
* @param ops libfs operations structure with function pointers to |
* file system implementation |
* @param rid Request ID of the VFS_OUT_OPEN_NODE request. |
* @param request VFS_OUT_OPEN_NODE request data itself. |
* @param rid Request ID of the VFS_OPEN_NODE request. |
* @param request VFS_OPEN_NODE request data itself. |
* |
*/ |
void libfs_open_node(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid, |
/branches/dd/uspace/lib/libfs/libfs.h |
---|
84,7 → 84,6 |
extern void libfs_mount(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *); |
extern void libfs_lookup(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *); |
extern void libfs_stat(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *); |
extern void libfs_open_node(libfs_ops_t *, fs_handle_t, ipc_callid_t, |
ipc_call_t *); |
/branches/dd/uspace/lib/libblock/libblock.c |
---|
46,13 → 46,13 |
#include <ipc/ipc.h> |
#include <as.h> |
#include <assert.h> |
#include <fibril_sync.h> |
#include <futex.h> |
#include <adt/list.h> |
#include <adt/hash_table.h> |
#include <mem.h> |
/** Lock protecting the device connection list */ |
static FIBRIL_MUTEX_INITIALIZE(dcl_lock); |
static futex_t dcl_lock = FUTEX_INITIALIZER; |
/** Device connection list head. */ |
static LIST_INITIALIZE(dcl_head); |
60,13 → 60,11 |
#define CACHE_BUCKETS (1 << CACHE_BUCKETS_LOG2) |
typedef struct { |
fibril_mutex_t lock; |
futex_t lock; |
size_t block_size; /**< Block size. */ |
unsigned block_count; /**< Total number of blocks. */ |
unsigned blocks_cached; /**< Number of cached blocks. */ |
hash_table_t block_hash; |
link_t free_head; |
enum cache_mode mode; |
} cache_t; |
typedef struct { |
73,7 → 71,6 |
link_t link; |
dev_handle_t dev_handle; |
int dev_phone; |
fibril_mutex_t com_area_lock; |
void *com_area; |
size_t com_size; |
void *bb_buf; |
82,22 → 79,19 |
cache_t *cache; |
} devcon_t; |
static int read_block(devcon_t *devcon, bn_t boff, size_t block_size); |
static int write_block(devcon_t *devcon, bn_t boff, size_t block_size); |
static devcon_t *devcon_search(dev_handle_t dev_handle) |
{ |
link_t *cur; |
fibril_mutex_lock(&dcl_lock); |
futex_down(&dcl_lock); |
for (cur = dcl_head.next; cur != &dcl_head; cur = cur->next) { |
devcon_t *devcon = list_get_instance(cur, devcon_t, link); |
if (devcon->dev_handle == dev_handle) { |
fibril_mutex_unlock(&dcl_lock); |
futex_up(&dcl_lock); |
return devcon; |
} |
} |
fibril_mutex_unlock(&dcl_lock); |
futex_up(&dcl_lock); |
return NULL; |
} |
114,7 → 108,6 |
link_initialize(&devcon->link); |
devcon->dev_handle = dev_handle; |
devcon->dev_phone = dev_phone; |
fibril_mutex_initialize(&devcon->com_area_lock); |
devcon->com_area = com_area; |
devcon->com_size = com_size; |
devcon->bb_buf = NULL; |
122,25 → 115,25 |
devcon->bb_size = 0; |
devcon->cache = NULL; |
fibril_mutex_lock(&dcl_lock); |
futex_down(&dcl_lock); |
for (cur = dcl_head.next; cur != &dcl_head; cur = cur->next) { |
devcon_t *d = list_get_instance(cur, devcon_t, link); |
if (d->dev_handle == dev_handle) { |
fibril_mutex_unlock(&dcl_lock); |
futex_up(&dcl_lock); |
free(devcon); |
return EEXIST; |
} |
} |
list_append(&devcon->link, &dcl_head); |
fibril_mutex_unlock(&dcl_lock); |
futex_up(&dcl_lock); |
return EOK; |
} |
static void devcon_remove(devcon_t *devcon) |
{ |
fibril_mutex_lock(&dcl_lock); |
futex_down(&dcl_lock); |
list_remove(&devcon->link); |
fibril_mutex_unlock(&dcl_lock); |
futex_up(&dcl_lock); |
} |
int block_init(dev_handle_t dev_handle, size_t com_size) |
214,16 → 207,14 |
if (!bb_buf) |
return ENOMEM; |
fibril_mutex_lock(&devcon->com_area_lock); |
rc = read_block(devcon, 0, size); |
off_t bufpos = 0; |
size_t buflen = 0; |
rc = block_read(dev_handle, &bufpos, &buflen, &off, |
bb_buf, size, size); |
if (rc != EOK) { |
fibril_mutex_unlock(&devcon->com_area_lock); |
free(bb_buf); |
return rc; |
} |
memcpy(bb_buf, devcon->com_area, size); |
fibril_mutex_unlock(&devcon->com_area_lock); |
devcon->bb_buf = bb_buf; |
devcon->bb_off = off; |
devcon->bb_size = size; |
259,8 → 250,7 |
.remove_callback = cache_remove_callback |
}; |
int block_cache_init(dev_handle_t dev_handle, size_t size, unsigned blocks, |
enum cache_mode mode) |
int block_cache_init(dev_handle_t dev_handle, size_t size, unsigned blocks) |
{ |
devcon_t *devcon = devcon_search(dev_handle); |
cache_t *cache; |
272,12 → 262,10 |
if (!cache) |
return ENOMEM; |
fibril_mutex_initialize(&cache->lock); |
futex_initialize(&cache->lock, 1); |
list_initialize(&cache->free_head); |
cache->block_size = size; |
cache->block_count = blocks; |
cache->blocks_cached = 0; |
cache->mode = mode; |
if (!hash_table_create(&cache->block_hash, CACHE_BUCKETS, 1, |
&cache_ops)) { |
289,23 → 277,17 |
return EOK; |
} |
#define CACHE_LO_WATERMARK 10 |
#define CACHE_HI_WATERMARK 20 |
static bool cache_can_grow(cache_t *cache) |
{ |
if (cache->blocks_cached < CACHE_LO_WATERMARK) |
return true; |
if (!list_empty(&cache->free_head)) |
return false; |
return true; |
} |
static void block_initialize(block_t *b) |
{ |
fibril_mutex_initialize(&b->lock); |
futex_initialize(&b->lock, 1); |
b->refcnt = 1; |
b->dirty = false; |
fibril_rwlock_initialize(&b->contents_lock); |
rwlock_initialize(&b->contents_lock); |
link_initialize(&b->free_link); |
link_initialize(&b->hash_link); |
} |
327,7 → 309,6 |
block_t *b; |
link_t *l; |
unsigned long key = boff; |
bn_t oboff; |
devcon = devcon_search(dev_handle); |
335,7 → 316,7 |
assert(devcon->cache); |
cache = devcon->cache; |
fibril_mutex_lock(&cache->lock); |
futex_down(&cache->lock); |
l = hash_table_find(&cache->block_hash, &key); |
if (l) { |
/* |
342,16 → 323,19 |
* We found the block in the cache. |
*/ |
b = hash_table_get_instance(l, block_t, hash_link); |
fibril_mutex_lock(&b->lock); |
futex_down(&b->lock); |
if (b->refcnt++ == 0) |
list_remove(&b->free_link); |
fibril_mutex_unlock(&b->lock); |
fibril_mutex_unlock(&cache->lock); |
futex_up(&b->lock); |
futex_up(&cache->lock); |
} else { |
/* |
* The block was not found in the cache. |
*/ |
int rc; |
off_t bufpos = 0; |
size_t buflen = 0; |
off_t pos = boff * cache->block_size; |
bool sync = false; |
if (cache_can_grow(cache)) { |
368,7 → 352,6 |
free(b); |
goto recycle; |
} |
cache->blocks_cached++; |
} else { |
/* |
* Try to recycle a block from the free list. |
378,9 → 361,8 |
assert(!list_empty(&cache->free_head)); |
l = cache->free_head.next; |
list_remove(l); |
b = list_get_instance(l, block_t, free_link); |
b = hash_table_get_instance(l, block_t, hash_link); |
sync = b->dirty; |
oboff = b->boff; |
temp_key = b->boff; |
hash_table_remove(&cache->block_hash, &temp_key, 1); |
} |
396,8 → 378,8 |
* kill concurent operations on the cache while doing I/O on the |
* block. |
*/ |
fibril_mutex_lock(&b->lock); |
fibril_mutex_unlock(&cache->lock); |
futex_down(&b->lock); |
futex_up(&cache->lock); |
if (sync) { |
/* |
404,11 → 386,7 |
* The block is dirty and needs to be written back to |
* the device before we can read in the new contents. |
*/ |
fibril_mutex_lock(&devcon->com_area_lock); |
memcpy(devcon->com_area, b->data, b->size); |
rc = write_block(devcon, oboff, cache->block_size); |
assert(rc == EOK); |
fibril_mutex_unlock(&devcon->com_area_lock); |
abort(); /* TODO: block_write() */ |
} |
if (!(flags & BLOCK_FLAGS_NOREAD)) { |
/* |
415,14 → 393,12 |
* The block contains old or no data. We need to read |
* the new contents from the device. |
*/ |
fibril_mutex_lock(&devcon->com_area_lock); |
rc = read_block(devcon, b->boff, cache->block_size); |
rc = block_read(dev_handle, &bufpos, &buflen, &pos, |
b->data, cache->block_size, cache->block_size); |
assert(rc == EOK); |
memcpy(b->data, devcon->com_area, cache->block_size); |
fibril_mutex_unlock(&devcon->com_area_lock); |
} |
fibril_mutex_unlock(&b->lock); |
futex_up(&b->lock); |
} |
return b; |
} |
437,62 → 413,25 |
{ |
devcon_t *devcon = devcon_search(block->dev_handle); |
cache_t *cache; |
int rc; |
assert(devcon); |
assert(devcon->cache); |
cache = devcon->cache; |
fibril_mutex_lock(&cache->lock); |
fibril_mutex_lock(&block->lock); |
futex_down(&cache->lock); |
futex_down(&block->lock); |
if (!--block->refcnt) { |
/* |
* Last reference to the block was dropped. Either free the |
* block or put it on the free list. |
* Last reference to the block was dropped, put the block on the |
* free list. |
*/ |
if (cache->blocks_cached > CACHE_HI_WATERMARK) { |
/* |
* Currently there are too many cached blocks. |
*/ |
if (block->dirty) { |
fibril_mutex_lock(&devcon->com_area_lock); |
memcpy(devcon->com_area, block->data, |
block->size); |
rc = write_block(devcon, block->boff, |
block->size); |
assert(rc == EOK); |
fibril_mutex_unlock(&devcon->com_area_lock); |
} |
/* |
* Take the block out of the cache and free it. |
*/ |
unsigned long key = block->boff; |
hash_table_remove(&cache->block_hash, &key, 1); |
free(block); |
free(block->data); |
cache->blocks_cached--; |
fibril_mutex_unlock(&cache->lock); |
return; |
} |
/* |
* Put the block on the free list. |
*/ |
list_append(&block->free_link, &cache->free_head); |
if (cache->mode != CACHE_MODE_WB && block->dirty) { |
fibril_mutex_lock(&devcon->com_area_lock); |
memcpy(devcon->com_area, block->data, block->size); |
rc = write_block(devcon, block->boff, block->size); |
assert(rc == EOK); |
fibril_mutex_unlock(&devcon->com_area_lock); |
block->dirty = false; |
} |
} |
fibril_mutex_unlock(&block->lock); |
fibril_mutex_unlock(&cache->lock); |
futex_up(&block->lock); |
futex_up(&cache->lock); |
} |
/** Read sequential data from a block device. |
/** Read data from a block device. |
* |
* @param dev_handle Device handle of the block device. |
* @param bufpos Pointer to the first unread valid offset within the |
506,8 → 445,9 |
* |
* @return EOK on success or a negative return code on failure. |
*/ |
int block_seqread(dev_handle_t dev_handle, off_t *bufpos, size_t *buflen, |
off_t *pos, void *dst, size_t size, size_t block_size) |
int |
block_read(dev_handle_t dev_handle, off_t *bufpos, size_t *buflen, off_t *pos, |
void *dst, size_t size, size_t block_size) |
{ |
off_t offset = 0; |
size_t left = size; |
514,7 → 454,6 |
devcon_t *devcon = devcon_search(dev_handle); |
assert(devcon); |
fibril_mutex_lock(&devcon->com_area_lock); |
while (left > 0) { |
size_t rd; |
535,70 → 474,21 |
left -= rd; |
} |
if (*bufpos == (off_t) *buflen) { |
if (*bufpos == *buflen) { |
/* Refill the communication buffer with a new block. */ |
int rc; |
rc = read_block(devcon, *pos / block_size, block_size); |
if (rc != EOK) { |
fibril_mutex_unlock(&devcon->com_area_lock); |
return rc; |
} |
ipcarg_t retval; |
int rc = async_req_2_1(devcon->dev_phone, BD_READ_BLOCK, |
*pos / block_size, block_size, &retval); |
if ((rc != EOK) || (retval != EOK)) |
return (rc != EOK ? rc : retval); |
*bufpos = 0; |
*buflen = block_size; |
} |
} |
fibril_mutex_unlock(&devcon->com_area_lock); |
return EOK; |
} |
/** Read block from block device. |
* |
* @param devcon Device connection. |
* @param boff Block index. |
* @param block_size Block size. |
* @param src Buffer for storing the data. |
* |
* @return EOK on success or negative error code on failure. |
*/ |
static int read_block(devcon_t *devcon, bn_t boff, size_t block_size) |
{ |
ipcarg_t retval; |
int rc; |
assert(devcon); |
rc = async_req_2_1(devcon->dev_phone, BD_READ_BLOCK, boff, block_size, |
&retval); |
if ((rc != EOK) || (retval != EOK)) |
return (rc != EOK ? rc : (int) retval); |
return EOK; |
} |
/** Write block to block device. |
* |
* @param devcon Device connection. |
* @param boff Block index. |
* @param block_size Block size. |
* @param src Buffer containing the data to write. |
* |
* @return EOK on success or negative error code on failure. |
*/ |
static int write_block(devcon_t *devcon, bn_t boff, size_t block_size) |
{ |
ipcarg_t retval; |
int rc; |
assert(devcon); |
rc = async_req_2_1(devcon->dev_phone, BD_WRITE_BLOCK, boff, block_size, |
&retval); |
if ((rc != EOK) || (retval != EOK)) |
return (rc != EOK ? rc : (int) retval); |
return EOK; |
} |
/** @} |
*/ |
/branches/dd/uspace/lib/libblock/libblock.h |
---|
39,7 → 39,8 |
#include <stdint.h> |
#include "../../srv/vfs/vfs.h" |
#include <fibril_sync.h> |
#include <futex.h> |
#include <rwlock.h> |
#include <adt/hash_table.h> |
#include <adt/list.h> |
62,14 → 63,14 |
typedef unsigned bn_t; /**< Block number type. */ |
typedef struct block { |
/** Mutex protecting the reference count. */ |
fibril_mutex_t lock; |
/** Futex protecting the reference count. */ |
futex_t lock; |
/** Number of references to the block_t structure. */ |
unsigned refcnt; |
/** If true, the block needs to be written back to the block device. */ |
bool dirty; |
/** Readers / Writer lock protecting the contents of the block. */ |
fibril_rwlock_t contents_lock; |
rwlock_t contents_lock; |
/** Handle of the device where the block resides. */ |
dev_handle_t dev_handle; |
/** Block offset on the block device. Counted in 'size'-byte blocks. */ |
84,14 → 85,6 |
void *data; |
} block_t; |
/** Caching mode */ |
enum cache_mode { |
/** Write-Through */ |
CACHE_MODE_WT, |
/** Write-Back */ |
CACHE_MODE_WB |
}; |
extern int block_init(dev_handle_t, size_t); |
extern void block_fini(dev_handle_t); |
98,13 → 91,13 |
extern int block_bb_read(dev_handle_t, off_t, size_t); |
extern void *block_bb_get(dev_handle_t); |
extern int block_cache_init(dev_handle_t, size_t, unsigned, enum cache_mode); |
extern int block_cache_init(dev_handle_t, size_t, unsigned); |
extern block_t *block_get(dev_handle_t, bn_t, int); |
extern block_t *block_get(dev_handle_t, bn_t, int flags); |
extern void block_put(block_t *); |
extern int block_seqread(dev_handle_t, off_t *, size_t *, off_t *, void *, |
size_t, size_t); |
extern int block_read(dev_handle_t, off_t *, size_t *, off_t *, void *, size_t, |
size_t); |
#endif |
/branches/dd/uspace/lib/libc/include/string.h |
---|
40,6 → 40,7 |
#include <bool.h> |
#define U_SPECIAL '?' |
#define U_BOM 0xfeff |
/** No size limit constant */ |
#define STR_NO_LIMIT ((size_t) -1) |
/branches/dd/uspace/lib/libc/include/vfs/vfs.h |
---|
55,8 → 55,8 |
extern int mount(const char *, const char *, const char *, const char *, |
unsigned int); |
extern void __stdio_init(int filc, fdi_node_t *filv[]); |
extern void __stdio_done(void); |
extern void stdio_init(int filc, fdi_node_t *filv[]); |
extern void stdio_done(void); |
extern int open_node(fdi_node_t *, int); |
extern int fd_phone(int); |
/branches/dd/uspace/lib/libc/include/async.h |
---|
43,10 → 43,15 |
typedef ipc_callid_t aid_t; |
typedef void (*async_client_conn_t)(ipc_callid_t callid, ipc_call_t *call); |
typedef void (*async_pending_t)(void); |
extern atomic_t async_futex; |
extern int __async_init(void); |
static inline void async_manager(void) |
{ |
fibril_switch(FIBRIL_TO_MANAGER); |
} |
extern ipc_callid_t async_get_call_timeout(ipc_call_t *call, suseconds_t usecs); |
static inline ipc_callid_t async_get_call(ipc_call_t *data) |
54,11 → 59,6 |
return async_get_call_timeout(data, 0); |
} |
static inline void async_manager(void) |
{ |
fibril_switch(FIBRIL_TO_MANAGER); |
} |
/* |
* User-friendly wrappers for async_send_fast() and async_send_slow(). The |
* macros are in the form async_send_m(), where m denotes the number of payload |
95,9 → 95,11 |
extern void async_usleep(suseconds_t timeout); |
extern void async_create_manager(void); |
extern void async_destroy_manager(void); |
extern int _async_init(void); |
extern void async_set_client_connection(async_client_conn_t conn); |
extern void async_set_interrupt_received(async_client_conn_t conn); |
extern void async_set_pending(async_pending_t pend); |
/* Wrappers for simple communication */ |
#define async_msg_0(phone, method) \ |
/branches/dd/uspace/lib/libc/include/stdio.h |
---|
37,21 → 37,17 |
#include <sys/types.h> |
#include <stdarg.h> |
#include <string.h> |
#include <adt/list.h> |
#define EOF (-1) |
/** Default size for stream I/O buffers */ |
#define BUFSIZ 4096 |
#define DEBUG(fmt, ...) \ |
{ \ |
char _buf[256]; \ |
int _n = snprintf(_buf, sizeof(_buf), fmt, ##__VA_ARGS__); \ |
if (_n > 0) \ |
(void) __SYSCALL3(SYS_KLOG, 1, (sysarg_t) _buf, str_size(_buf)); \ |
} |
{ \ |
char buf[256]; \ |
int n = snprintf(buf, sizeof(buf), fmt, ##__VA_ARGS__); \ |
if (n > 0) \ |
(void) __SYSCALL3(SYS_KLOG, 1, (sysarg_t) buf, str_size(buf)); \ |
} |
#ifndef SEEK_SET |
#define SEEK_SET 0 |
59,15 → 55,6 |
#define SEEK_END 2 |
#endif |
enum _buffer_type { |
/** No buffering */ |
_IONBF, |
/** Line buffering */ |
_IOLBF, |
/** Full buffering */ |
_IOFBF |
}; |
typedef struct { |
/** Linked list pointer. */ |
link_t link; |
86,15 → 73,6 |
/** Phone to the file provider */ |
int phone; |
/** Buffering type */ |
enum _buffer_type btype; |
/** Buffer */ |
uint8_t *buf; |
/** Buffer size */ |
size_t buf_size; |
/** Buffer I/O pointer */ |
uint8_t *buf_head; |
} FILE; |
extern FILE *stdin; |
143,8 → 121,6 |
extern int ferror(FILE *); |
extern void clearerr(FILE *); |
extern void setvbuf(FILE *, void *, int, size_t); |
/* Misc file functions */ |
extern int rename(const char *, const char *); |
/branches/dd/uspace/lib/libc/include/task.h |
---|
39,18 → 39,11 |
typedef uint64_t task_id_t; |
typedef enum { |
TASK_EXIT_NORMAL, |
TASK_EXIT_UNEXPECTED |
} task_exit_t; |
extern task_id_t task_get_id(void); |
extern int task_set_name(const char *name); |
extern task_id_t task_spawn(const char *path, char *const argv[]); |
extern int task_wait(task_id_t id, task_exit_t *texit, int *retval); |
extern int task_retval(int val); |
extern int task_wait(task_id_t id); |
#endif |
/** @} |
/branches/dd/uspace/lib/libc/include/unistd.h |
---|
65,6 → 65,7 |
extern int chdir(const char *); |
extern void _exit(int status) __attribute__ ((noreturn)); |
extern void *sbrk(ssize_t incr); |
extern int usleep(unsigned long usec); |
extern unsigned int sleep(unsigned int seconds); |
/branches/dd/uspace/lib/libc/include/fibril.h |
---|
75,7 → 75,7 |
/** Fibril-local variable specifier */ |
#define fibril_local __thread |
extern int context_save(context_t *c) __attribute__ ((returns_twice)); |
extern int context_save(context_t *c); |
extern void context_restore(context_t *c) __attribute__ ((noreturn)); |
extern fid_t fibril_create(int (*func)(void *), void *arg); |
/branches/dd/uspace/lib/libc/include/io/console.h |
---|
43,13 → 43,6 |
KEY_RELEASE |
} console_ev_type_t; |
enum { |
CONSOLE_CCAP_NONE = 0, |
CONSOLE_CCAP_STYLE, |
CONSOLE_CCAP_INDEXED, |
CONSOLE_CCAP_RGB |
}; |
/** Console event structure. */ |
typedef struct { |
/** Press or release event. */ |
75,7 → 68,6 |
extern void console_set_rgb_color(int phone, int fg_color, int bg_color); |
extern void console_cursor_visibility(int phone, bool show); |
extern int console_get_color_cap(int phone, int *ccap); |
extern void console_kcon_enable(int phone); |
extern bool console_get_event(int phone, console_event_t *event); |
/branches/dd/uspace/lib/libc/include/adt/gcdlcm.h |
---|
File deleted |
/branches/dd/uspace/lib/libc/include/macros.h |
---|
35,9 → 35,6 |
#ifndef LIBC_MACROS_H_ |
#define LIBC_MACROS_H_ |
#define min(a, b) ((a) < (b) ? (a) : (b)) |
#define max(a, b) ((a) > (b) ? (a) : (b)) |
#define SIZE2KB(size) ((size) >> 10) |
#define SIZE2MB(size) ((size) >> 20) |
/branches/dd/uspace/lib/libc/include/ipc/devmap.h |
---|
28,7 → 28,7 |
/** @addtogroup devmap |
* @{ |
*/ |
*/ |
#ifndef DEVMAP_DEVMAP_H_ |
#define DEVMAP_DEVMAP_H_ |
48,8 → 48,6 |
DEVMAP_DEVICE_UNREGISTER, |
DEVMAP_DEVICE_GET_NAME, |
DEVMAP_DEVICE_GET_HANDLE, |
DEVMAP_DEVICE_NULL_CREATE, |
DEVMAP_DEVICE_NULL_DESTROY, |
DEVMAP_DEVICE_GET_COUNT, |
DEVMAP_DEVICE_GET_DEVICES |
} devmap_request_t; |
/branches/dd/uspace/lib/libc/include/ipc/vfs.h |
---|
57,40 → 57,36 |
} vfs_info_t; |
typedef enum { |
VFS_IN_OPEN = IPC_FIRST_USER_METHOD, |
VFS_IN_OPEN_NODE, |
VFS_IN_READ, |
VFS_IN_WRITE, |
VFS_IN_SEEK, |
VFS_IN_TRUNCATE, |
VFS_IN_FSTAT, |
VFS_IN_CLOSE, |
VFS_IN_MOUNT, |
VFS_IN_UNMOUNT, |
VFS_IN_SYNC, |
VFS_IN_REGISTER, |
VFS_IN_MKDIR, |
VFS_IN_UNLINK, |
VFS_IN_RENAME, |
VFS_IN_STAT |
} vfs_in_request_t; |
VFS_OPEN_NODE = IPC_FIRST_USER_METHOD, |
VFS_READ, |
VFS_WRITE, |
VFS_TRUNCATE, |
VFS_MOUNT, |
VFS_UNMOUNT, |
VFS_DEVICE, |
VFS_SYNC, |
VFS_CLOSE, |
VFS_LAST_CMN /* keep this the last member of this enum */ |
} vfs_request_cmn_t; |
typedef enum { |
VFS_OUT_OPEN_NODE = IPC_FIRST_USER_METHOD, |
VFS_OUT_READ, |
VFS_OUT_WRITE, |
VFS_OUT_TRUNCATE, |
VFS_OUT_CLOSE, |
VFS_OUT_MOUNT, |
VFS_OUT_MOUNTED, |
VFS_OUT_UNMOUNT, |
VFS_OUT_SYNC, |
VFS_OUT_STAT, |
VFS_OUT_LOOKUP, |
VFS_OUT_DESTROY, |
VFS_OUT_LAST |
} vfs_out_request_t; |
VFS_LOOKUP = VFS_LAST_CMN, |
VFS_MOUNTED, |
VFS_DESTROY, |
VFS_LAST_CLNT /* keep this the last member of this enum */ |
} vfs_request_clnt_t; |
typedef enum { |
VFS_REGISTER = VFS_LAST_CMN, |
VFS_OPEN, |
VFS_SEEK, |
VFS_MKDIR, |
VFS_UNLINK, |
VFS_RENAME, |
VFS_NODE, |
VFS_LAST_SRV /* keep this the last member of this enum */ |
} vfs_request_srv_t; |
/* |
* Lookup flags. |
*/ |
/branches/dd/uspace/lib/libc/include/ipc/ns.h |
---|
39,9 → 39,7 |
typedef enum { |
NS_PING = IPC_FIRST_USER_METHOD, |
NS_TASK_WAIT, |
NS_ID_INTRO, |
NS_RETVAL |
NS_TASK_WAIT |
} ns_request_t; |
#endif |
/branches/dd/uspace/lib/libc/include/ipc/console.h |
---|
39,8 → 39,7 |
#include <ipc/vfs.h> |
typedef enum { |
CONSOLE_GET_SIZE = VFS_OUT_LAST, |
CONSOLE_GET_COLOR_CAP, |
CONSOLE_GET_SIZE = VFS_LAST_SRV, |
CONSOLE_GET_EVENT, |
CONSOLE_GOTO, |
CONSOLE_CLEAR, |
/branches/dd/uspace/lib/libc/include/ipc/fb.h |
---|
41,7 → 41,6 |
FB_PUTCHAR = IPC_FIRST_USER_METHOD, |
FB_CLEAR, |
FB_GET_CSIZE, |
FB_GET_COLOR_CAP, |
FB_CURSOR_VISIBILITY, |
FB_CURSOR_GOTO, |
FB_SCROLL, |
72,13 → 71,6 |
FB_SCREEN_RECLAIM |
} fb_request_t; |
enum { |
FB_CCAP_NONE = 0, |
FB_CCAP_STYLE, |
FB_CCAP_INDEXED, |
FB_CCAP_RGB |
}; |
#endif |
/** @} |
/branches/dd/uspace/lib/libc/include/errno.h |
---|
35,13 → 35,12 |
#ifndef LIBC_ERRNO_H_ |
#define LIBC_ERRNO_H_ |
#include <kernel/errno.h> |
#include <fibril.h> |
/* TODO: support threads/fibrils */ |
extern int _errno; |
#define errno _errno |
#include <kernel/errno.h> |
#define EMFILE (-17) |
#define ENAMETOOLONG (-256) |
#define EISDIR (-257) |
/branches/dd/uspace/lib/libc/include/devmap.h |
---|
47,9 → 47,6 |
extern int devmap_device_get_handle(const char *, dev_handle_t *, unsigned int); |
extern int devmap_device_connect(dev_handle_t, unsigned int); |
extern int devmap_null_create(void); |
extern void devmap_null_destroy(int); |
extern ipcarg_t devmap_device_get_count(void); |
extern ipcarg_t devmap_device_get_devices(ipcarg_t, dev_desc_t *); |
/branches/dd/uspace/lib/libc/include/sys/stat.h |
---|
36,26 → 36,7 |
#define LIBC_SYS_STAT_H_ |
#include <sys/types.h> |
#include <bool.h> |
#include <ipc/vfs.h> |
#include <ipc/devmap.h> |
struct stat { |
fs_handle_t fs_handle; |
dev_handle_t dev_handle; |
fs_index_t index; |
unsigned lnkcnt; |
bool is_file; |
off_t size; |
union { |
struct { |
dev_handle_t device; |
} devfs_stat; |
}; |
}; |
extern int fstat(int, struct stat *); |
extern int stat(const char *, struct stat *); |
extern int mkdir(const char *, mode_t); |
#endif |
/branches/dd/uspace/lib/libc/include/byteorder.h |
---|
35,47 → 35,48 |
#ifndef LIBC_BYTEORDER_H_ |
#define LIBC_BYTEORDER_H_ |
#include <libarch/byteorder.h> |
#include <stdint.h> |
#if !(defined(__BE__) ^ defined(__LE__)) |
#error The architecture must be either big-endian or little-endian. |
#if !(defined(ARCH_IS_BIG_ENDIAN) ^ defined(ARCH_IS_LITTLE_ENDIAN)) |
#error The architecture must be either big-endian or little-endian. |
#endif |
#ifdef __BE__ |
#ifdef ARCH_IS_BIG_ENDIAN |
#define uint16_t_le2host(n) (uint16_t_byteorder_swap(n)) |
#define uint32_t_le2host(n) (uint32_t_byteorder_swap(n)) |
#define uint64_t_le2host(n) (uint64_t_byteorder_swap(n)) |
#define uint16_t_le2host(n) uint16_t_byteorder_swap(n) |
#define uint32_t_le2host(n) uint32_t_byteorder_swap(n) |
#define uint64_t_le2host(n) uint64_t_byteorder_swap(n) |
#define uint16_t_be2host(n) (n) |
#define uint32_t_be2host(n) (n) |
#define uint64_t_be2host(n) (n) |
#define uint16_t_be2host(n) (n) |
#define uint32_t_be2host(n) (n) |
#define uint64_t_be2host(n) (n) |
#define host2uint16_t_le(n) (uint16_t_byteorder_swap(n)) |
#define host2uint32_t_le(n) (uint32_t_byteorder_swap(n)) |
#define host2uint64_t_le(n) (uint64_t_byteorder_swap(n)) |
#define host2uint16_t_le(n) uint16_t_byteorder_swap(n) |
#define host2uint32_t_le(n) uint32_t_byteorder_swap(n) |
#define host2uint64_t_le(n) uint64_t_byteorder_swap(n) |
#define host2uint16_t_be(n) (n) |
#define host2uint32_t_be(n) (n) |
#define host2uint64_t_be(n) (n) |
#define host2uint16_t_be(n) (n) |
#define host2uint32_t_be(n) (n) |
#define host2uint64_t_be(n) (n) |
#else |
#define uint16_t_le2host(n) (n) |
#define uint32_t_le2host(n) (n) |
#define uint64_t_le2host(n) (n) |
#define uint16_t_le2host(n) (n) |
#define uint32_t_le2host(n) (n) |
#define uint64_t_le2host(n) (n) |
#define uint16_t_be2host(n) (uint16_t_byteorder_swap(n)) |
#define uint32_t_be2host(n) (uint32_t_byteorder_swap(n)) |
#define uint64_t_be2host(n) (uint64_t_byteorder_swap(n)) |
#define uint16_t_be2host(n) uint16_t_byteorder_swap(n) |
#define uint32_t_be2host(n) uint32_t_byteorder_swap(n) |
#define uint64_t_be2host(n) uint64_t_byteorder_swap(n) |
#define host2uint16_t_le(n) (n) |
#define host2uint32_t_le(n) (n) |
#define host2uint64_t_le(n) (n) |
#define host2uint16_t_le(n) (n) |
#define host2uint32_t_le(n) (n) |
#define host2uint64_t_le(n) (n) |
#define host2uint16_t_be(n) (uint16_t_byteorder_swap(n)) |
#define host2uint32_t_be(n) (uint32_t_byteorder_swap(n)) |
#define host2uint64_t_be(n) (uint64_t_byteorder_swap(n)) |
#define host2uint16_t_be(n) uint16_t_byteorder_swap(n) |
#define host2uint32_t_be(n) uint32_t_byteorder_swap(n) |
#define host2uint64_t_be(n) uint64_t_byteorder_swap(n) |
#endif |
/branches/dd/uspace/lib/libc/include/getopt.h |
---|
58,7 → 58,7 |
}; |
/* HelenOS Port - These need to be exposed for legacy getopt() */ |
extern const char *optarg; |
extern char *optarg; |
extern int optind, opterr, optopt; |
extern int optreset; |
/branches/dd/uspace/lib/libc/include/mem.h |
---|
39,9 → 39,9 |
#define bzero(ptr, len) memset((ptr), 0, (len)) |
extern void *memset(void *, int, size_t); |
extern void *memcpy(void *, const void *, size_t); |
extern void *memmove(void *, const void *, size_t); |
extern void * memset(void *, int, size_t); |
extern void * memcpy(void *, const void *, size_t); |
extern void * memmove(void *, const void *, size_t); |
extern int bcmp(const char *, const char *, size_t); |
/branches/dd/uspace/lib/libc/include/bitops.h |
---|
26,7 → 26,7 |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup generic |
/** @addtogroup generic |
* @{ |
*/ |
/** @file |
42,10 → 42,10 |
* |
* If number is zero, it returns 0 |
*/ |
static inline unsigned int fnzb32(uint32_t arg) |
static inline int fnzb32(uint32_t arg) |
{ |
unsigned int n = 0; |
int n = 0; |
if (arg >> 16) { |
arg >>= 16; |
n += 16; |
74,22 → 74,19 |
return n; |
} |
static inline unsigned int fnzb64(uint64_t arg) |
static inline int fnzb64(uint64_t arg) |
{ |
unsigned int n = 0; |
int n = 0; |
if (arg >> 32) { |
arg >>= 32; |
n += 32; |
} |
return (n + fnzb32((uint32_t) arg)); |
return n + fnzb32((uint32_t) arg); |
} |
static inline unsigned int fnzb(size_t arg) |
{ |
return fnzb64(arg); |
} |
#define fnzb(x) fnzb32(x) |
#endif |
/branches/dd/uspace/lib/libc/include/stdlib.h |
---|
38,10 → 38,10 |
#include <unistd.h> |
#include <malloc.h> |
#define abort() _exit(1) |
#define exit(status) _exit((status)) |
#define abort() _exit(1) |
#define exit(status) _exit((status)) |
#define RAND_MAX 714025 |
#define RAND_MAX 714025 |
extern long int random(void); |
extern void srandom(unsigned int seed); |
50,7 → 50,6 |
{ |
return random(); |
} |
static inline void srand(unsigned int seed) |
{ |
srandom(seed); |
/branches/dd/uspace/lib/libc/include/malloc.h |
---|
1,51 → 1,537 |
/* |
* Copyright (c) 2009 Martin Decky |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
Default header file for malloc-2.8.x, written by Doug Lea |
and released to the public domain, as explained at |
http://creativecommons.org/licenses/publicdomain. |
last update: Mon Aug 15 08:55:52 2005 Doug Lea (dl at gee) |
/** @addtogroup libc |
* @{ |
This header is for ANSI C/C++ only. You can set any of |
the following #defines before including: |
* If USE_DL_PREFIX is defined, it is assumed that malloc.c |
was also compiled with this option, so all routines |
have names starting with "dl". |
* If HAVE_USR_INCLUDE_MALLOC_H is defined, it is assumed that this |
file will be #included AFTER <malloc.h>. This is needed only if |
your system defines a struct mallinfo that is incompatible with the |
standard one declared here. Otherwise, you can include this file |
INSTEAD of your system system <malloc.h>. At least on ANSI, all |
declarations should be compatible with system versions |
* If MSPACES is defined, declarations for mspace versions are included. |
*/ |
#ifndef MALLOC_280_H |
#define MALLOC_280_H |
#ifdef __cplusplus |
extern "C" { |
#endif |
#include <stddef.h> /* for size_t */ |
#if !ONLY_MSPACES |
#ifndef USE_DL_PREFIX |
#define dlcalloc calloc |
#define dlfree free |
#define dlmalloc malloc |
#define dlmemalign memalign |
#define dlrealloc realloc |
#define dlvalloc valloc |
#define dlpvalloc pvalloc |
#define dlmallinfo mallinfo |
#define dlmallopt mallopt |
#define dlmalloc_trim malloc_trim |
#define dlmalloc_stats malloc_stats |
#define dlmalloc_usable_size malloc_usable_size |
#define dlmalloc_footprint malloc_footprint |
#define dlmalloc_max_footprint malloc_max_footprint |
#define dlindependent_calloc independent_calloc |
#define dlindependent_comalloc independent_comalloc |
#endif /* USE_DL_PREFIX */ |
/* |
malloc(size_t n) |
Returns a pointer to a newly allocated chunk of at least n bytes, or |
null if no space is available, in which case errno is set to ENOMEM |
on ANSI C systems. |
If n is zero, malloc returns a minimum-sized chunk. (The minimum |
size is 16 bytes on most 32bit systems, and 32 bytes on 64bit |
systems.) Note that size_t is an unsigned type, so calls with |
arguments that would be negative if signed are interpreted as |
requests for huge amounts of space, which will often fail. The |
maximum supported value of n differs across systems, but is in all |
cases less than the maximum representable value of a size_t. |
*/ |
void* dlmalloc(size_t); |
/* |
free(void* p) |
Releases the chunk of memory pointed to by p, that had been previously |
allocated using malloc or a related routine such as realloc. |
It has no effect if p is null. If p was not malloced or already |
freed, free(p) will by default cuase the current program to abort. |
*/ |
void dlfree(void*); |
/* |
calloc(size_t n_elements, size_t element_size); |
Returns a pointer to n_elements * element_size bytes, with all locations |
set to zero. |
*/ |
void* dlcalloc(size_t, size_t); |
/* |
realloc(void* p, size_t n) |
Returns a pointer to a chunk of size n that contains the same data |
as does chunk p up to the minimum of (n, p's size) bytes, or null |
if no space is available. |
The returned pointer may or may not be the same as p. The algorithm |
prefers extending p in most cases when possible, otherwise it |
employs the equivalent of a malloc-copy-free sequence. |
If p is null, realloc is equivalent to malloc. |
If space is not available, realloc returns null, errno is set (if on |
ANSI) and p is NOT freed. |
if n is for fewer bytes than already held by p, the newly unused |
space is lopped off and freed if possible. realloc with a size |
argument of zero (re)allocates a minimum-sized chunk. |
The old unix realloc convention of allowing the last-free'd chunk |
to be used as an argument to realloc is not supported. |
*/ |
void* dlrealloc(void*, size_t); |
/* |
memalign(size_t alignment, size_t n); |
Returns a pointer to a newly allocated chunk of n bytes, aligned |
in accord with the alignment argument. |
The alignment argument should be a power of two. If the argument is |
not a power of two, the nearest greater power is used. |
8-byte alignment is guaranteed by normal malloc calls, so don't |
bother calling memalign with an argument of 8 or less. |
Overreliance on memalign is a sure way to fragment space. |
*/ |
void* dlmemalign(size_t, size_t); |
/* |
valloc(size_t n); |
Equivalent to memalign(pagesize, n), where pagesize is the page |
size of the system. If the pagesize is unknown, 4096 is used. |
*/ |
void* dlvalloc(size_t); |
/* |
mallopt(int parameter_number, int parameter_value) |
Sets tunable parameters The format is to provide a |
(parameter-number, parameter-value) pair. mallopt then sets the |
corresponding parameter to the argument value if it can (i.e., so |
long as the value is meaningful), and returns 1 if successful else |
0. SVID/XPG/ANSI defines four standard param numbers for mallopt, |
normally defined in malloc.h. None of these are use in this malloc, |
so setting them has no effect. But this malloc also supports other |
options in mallopt: |
Symbol param # default allowed param values |
M_TRIM_THRESHOLD -1 2*1024*1024 any (-1U disables trimming) |
M_GRANULARITY -2 page size any power of 2 >= page size |
M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support) |
*/ |
int dlmallopt(int, int); |
#define M_TRIM_THRESHOLD (-1) |
#define M_GRANULARITY (-2) |
#define M_MMAP_THRESHOLD (-3) |
/* |
malloc_footprint(); |
Returns the number of bytes obtained from the system. The total |
number of bytes allocated by malloc, realloc etc., is less than this |
value. Unlike mallinfo, this function returns only a precomputed |
result, so can be called frequently to monitor memory consumption. |
Even if locks are otherwise defined, this function does not use them, |
so results might not be up to date. |
*/ |
size_t dlmalloc_footprint(void); |
size_t dlmalloc_max_footprint(void); |
#if !NO_MALLINFO |
/* |
mallinfo() |
Returns (by copy) a struct containing various summary statistics: |
arena: current total non-mmapped bytes allocated from system |
ordblks: the number of free chunks |
smblks: always zero. |
hblks: current number of mmapped regions |
hblkhd: total bytes held in mmapped regions |
usmblks: the maximum total allocated space. This will be greater |
than current total if trimming has occurred. |
fsmblks: always zero |
uordblks: current total allocated space (normal or mmapped) |
fordblks: total free space |
keepcost: the maximum number of bytes that could ideally be released |
back to system via malloc_trim. ("ideally" means that |
it ignores page restrictions etc.) |
Because these fields are ints, but internal bookkeeping may |
be kept as longs, the reported values may wrap around zero and |
thus be inaccurate. |
*/ |
#ifndef HAVE_USR_INCLUDE_MALLOC_H |
#ifndef _MALLOC_H |
#ifndef MALLINFO_FIELD_TYPE |
#define MALLINFO_FIELD_TYPE size_t |
#endif /* MALLINFO_FIELD_TYPE */ |
struct mallinfo { |
MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */ |
MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */ |
MALLINFO_FIELD_TYPE smblks; /* always 0 */ |
MALLINFO_FIELD_TYPE hblks; /* always 0 */ |
MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */ |
MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */ |
MALLINFO_FIELD_TYPE fsmblks; /* always 0 */ |
MALLINFO_FIELD_TYPE uordblks; /* total allocated space */ |
MALLINFO_FIELD_TYPE fordblks; /* total free space */ |
MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */ |
}; |
#endif /* _MALLOC_H */ |
#endif /* HAVE_USR_INCLUDE_MALLOC_H */ |
struct mallinfo dlmallinfo(void); |
#endif /* NO_MALLINFO */ |
/* |
independent_calloc(size_t n_elements, size_t element_size, void* chunks[]); |
independent_calloc is similar to calloc, but instead of returning a |
single cleared space, it returns an array of pointers to n_elements |
independent elements that can hold contents of size elem_size, each |
of which starts out cleared, and can be independently freed, |
realloc'ed etc. The elements are guaranteed to be adjacently |
allocated (this is not guaranteed to occur with multiple callocs or |
mallocs), which may also improve cache locality in some |
applications. |
The "chunks" argument is optional (i.e., may be null, which is |
probably the most typical usage). If it is null, the returned array |
is itself dynamically allocated and should also be freed when it is |
no longer needed. Otherwise, the chunks array must be of at least |
n_elements in length. It is filled in with the pointers to the |
chunks. |
In either case, independent_calloc returns this pointer array, or |
null if the allocation failed. If n_elements is zero and "chunks" |
is null, it returns a chunk representing an array with zero elements |
(which should be freed if not wanted). |
Each element must be individually freed when it is no longer |
needed. If you'd like to instead be able to free all at once, you |
should instead use regular calloc and assign pointers into this |
space to represent elements. (In this case though, you cannot |
independently free elements.) |
independent_calloc simplifies and speeds up implementations of many |
kinds of pools. It may also be useful when constructing large data |
structures that initially have a fixed number of fixed-sized nodes, |
but the number is not known at compile time, and some of the nodes |
may later need to be freed. For example: |
struct Node { int item; struct Node* next; }; |
struct Node* build_list() { |
struct Node** pool; |
int n = read_number_of_nodes_needed(); |
if (n <= 0) return 0; |
pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0); |
if (pool == 0) die(); |
// organize into a linked list... |
struct Node* first = pool[0]; |
for (i = 0; i < n-1; ++i) |
pool[i]->next = pool[i+1]; |
free(pool); // Can now free the array (or not, if it is needed later) |
return first; |
} |
*/ |
void** dlindependent_calloc(size_t, size_t, void**); |
/* |
independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]); |
independent_comalloc allocates, all at once, a set of n_elements |
chunks with sizes indicated in the "sizes" array. It returns |
an array of pointers to these elements, each of which can be |
independently freed, realloc'ed etc. The elements are guaranteed to |
be adjacently allocated (this is not guaranteed to occur with |
multiple callocs or mallocs), which may also improve cache locality |
in some applications. |
The "chunks" argument is optional (i.e., may be null). If it is null |
the returned array is itself dynamically allocated and should also |
be freed when it is no longer needed. Otherwise, the chunks array |
must be of at least n_elements in length. It is filled in with the |
pointers to the chunks. |
In either case, independent_comalloc returns this pointer array, or |
null if the allocation failed. If n_elements is zero and chunks is |
null, it returns a chunk representing an array with zero elements |
(which should be freed if not wanted). |
Each element must be individually freed when it is no longer |
needed. If you'd like to instead be able to free all at once, you |
should instead use a single regular malloc, and assign pointers at |
particular offsets in the aggregate space. (In this case though, you |
cannot independently free elements.) |
independent_comallac differs from independent_calloc in that each |
element may have a different size, and also that it does not |
automatically clear elements. |
independent_comalloc can be used to speed up allocation in cases |
where several structs or objects must always be allocated at the |
same time. For example: |
struct Head { ... } |
struct Foot { ... } |
void send_message(char* msg) { |
int msglen = strlen(msg); |
size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) }; |
void* chunks[3]; |
if (independent_comalloc(3, sizes, chunks) == 0) |
die(); |
struct Head* head = (struct Head*)(chunks[0]); |
char* body = (char*)(chunks[1]); |
struct Foot* foot = (struct Foot*)(chunks[2]); |
// ... |
} |
In general though, independent_comalloc is worth using only for |
larger values of n_elements. For small values, you probably won't |
detect enough difference from series of malloc calls to bother. |
Overuse of independent_comalloc can increase overall memory usage, |
since it cannot reuse existing noncontiguous small chunks that |
might be available for some of the elements. |
*/ |
void** dlindependent_comalloc(size_t, size_t*, void**); |
/* |
pvalloc(size_t n); |
Equivalent to valloc(minimum-page-that-holds(n)), that is, |
round up n to nearest pagesize. |
*/ |
/** @file |
*/ |
void* dlpvalloc(size_t); |
#ifndef LIBC_MALLOC_H_ |
#define LIBC_MALLOC_H_ |
/* |
malloc_trim(size_t pad); |
#include <sys/types.h> |
If possible, gives memory back to the system (via negative arguments |
to sbrk) if there is unused memory at the `high' end of the malloc |
pool or in unused MMAP segments. You can call this after freeing |
large blocks of memory to potentially reduce the system-level memory |
requirements of a program. However, it cannot guarantee to reduce |
memory. Under some allocation patterns, some large free blocks of |
memory will be locked between two used chunks, so they cannot be |
given back to the system. |
extern void __heap_init(void); |
extern uintptr_t get_max_heap_addr(void); |
The `pad' argument to malloc_trim represents the amount of free |
trailing space to leave untrimmed. If this argument is zero, only |
the minimum amount of memory to maintain internal data structures |
will be left. Non-zero arguments can be supplied to maintain enough |
trailing space to service future expected allocations without having |
to re-obtain memory from the system. |
extern void *malloc(const size_t size); |
extern void *memalign(const size_t align, const size_t size); |
extern void *realloc(const void *addr, const size_t size); |
extern void free(const void *addr); |
Malloc_trim returns 1 if it actually released any memory, else 0. |
*/ |
int dlmalloc_trim(size_t); |
/* |
malloc_usable_size(void* p); |
Returns the number of bytes you can actually use in |
an allocated chunk, which may be more than you requested (although |
often not) due to alignment and minimum size constraints. |
You can use this many bytes without worrying about |
overwriting other allocated objects. This is not a particularly great |
programming practice. malloc_usable_size can be more useful in |
debugging and assertions, for example: |
p = malloc(n); |
assert(malloc_usable_size(p) >= 256); |
*/ |
size_t dlmalloc_usable_size(void*); |
/* |
malloc_stats(); |
Prints on stderr the amount of space obtained from the system (both |
via sbrk and mmap), the maximum amount (which may be more than |
current if malloc_trim and/or munmap got called), and the current |
number of bytes allocated via malloc (or realloc, etc) but not yet |
freed. Note that this is the number of bytes allocated, not the |
number requested. It will be larger than the number requested |
because of alignment and bookkeeping overhead. Because it includes |
alignment wastage as being in use, this figure may be greater than |
zero even when no user-level chunks are allocated. |
The reported current and maximum system memory can be inaccurate if |
a program makes other calls to system memory allocation functions |
(normally sbrk) outside of malloc. |
malloc_stats prints only the most commonly interesting statistics. |
More information can be obtained by calling mallinfo. |
*/ |
void dlmalloc_stats(void); |
#endif /* !ONLY_MSPACES */ |
#if MSPACES |
/* |
mspace is an opaque type representing an independent |
region of space that supports mspace_malloc, etc. |
*/ |
typedef void* mspace; |
/* |
create_mspace creates and returns a new independent space with the |
given initial capacity, or, if 0, the default granularity size. It |
returns null if there is no system memory available to create the |
space. If argument locked is non-zero, the space uses a separate |
lock to control access. The capacity of the space will grow |
dynamically as needed to service mspace_malloc requests. You can |
control the sizes of incremental increases of this space by |
compiling with a different DEFAULT_GRANULARITY or dynamically |
setting with mallopt(M_GRANULARITY, value). |
*/ |
mspace create_mspace(size_t capacity, int locked); |
/* |
destroy_mspace destroys the given space, and attempts to return all |
of its memory back to the system, returning the total number of |
bytes freed. After destruction, the results of access to all memory |
used by the space become undefined. |
*/ |
size_t destroy_mspace(mspace msp); |
/* |
create_mspace_with_base uses the memory supplied as the initial base |
of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this |
space is used for bookkeeping, so the capacity must be at least this |
large. (Otherwise 0 is returned.) When this initial space is |
exhausted, additional memory will be obtained from the system. |
Destroying this space will deallocate all additionally allocated |
space (if possible) but not the initial base. |
*/ |
mspace create_mspace_with_base(void* base, size_t capacity, int locked); |
/* |
mspace_malloc behaves as malloc, but operates within |
the given space. |
*/ |
void* mspace_malloc(mspace msp, size_t bytes); |
/* |
mspace_free behaves as free, but operates within |
the given space. |
If compiled with FOOTERS==1, mspace_free is not actually needed. |
free may be called instead of mspace_free because freed chunks from |
any space are handled by their originating spaces. |
*/ |
void mspace_free(mspace msp, void* mem); |
/* |
mspace_realloc behaves as realloc, but operates within |
the given space. |
If compiled with FOOTERS==1, mspace_realloc is not actually |
needed. realloc may be called instead of mspace_realloc because |
realloced chunks from any space are handled by their originating |
spaces. |
*/ |
void* mspace_realloc(mspace msp, void* mem, size_t newsize); |
/* |
mspace_calloc behaves as calloc, but operates within |
the given space. |
*/ |
void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size); |
/* |
mspace_memalign behaves as memalign, but operates within |
the given space. |
*/ |
void* mspace_memalign(mspace msp, size_t alignment, size_t bytes); |
/* |
mspace_independent_calloc behaves as independent_calloc, but |
operates within the given space. |
*/ |
void** mspace_independent_calloc(mspace msp, size_t n_elements, |
size_t elem_size, void* chunks[]); |
/* |
mspace_independent_comalloc behaves as independent_comalloc, but |
operates within the given space. |
*/ |
void** mspace_independent_comalloc(mspace msp, size_t n_elements, |
size_t sizes[], void* chunks[]); |
/* |
mspace_footprint() returns the number of bytes obtained from the |
system for this space. |
*/ |
size_t mspace_footprint(mspace msp); |
#if !NO_MALLINFO |
/* |
mspace_mallinfo behaves as mallinfo, but reports properties of |
the given space. |
*/ |
struct mallinfo mspace_mallinfo(mspace msp); |
#endif /* NO_MALLINFO */ |
/* |
mspace_malloc_stats behaves as malloc_stats, but reports |
properties of the given space. |
*/ |
void mspace_malloc_stats(mspace msp); |
/* |
mspace_trim behaves as malloc_trim, but |
operates within the given space. |
*/ |
int mspace_trim(mspace msp, size_t pad); |
/* |
An alias for mallopt. |
*/ |
int mspace_mallopt(int, int); |
#endif /* MSPACES */ |
#ifdef __cplusplus |
}; /* end of extern "C" */ |
#endif |
/** @} |
#endif /* MALLOC_280_H */ |
/** @} |
*/ |
/branches/dd/uspace/lib/libc/Makefile.toolchain |
---|
27,10 → 27,9 |
# |
CFLAGS = -I$(LIBC_PREFIX)/include -O3 -imacros $(LIBC_PREFIX)/../../../config.h \ |
-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32$(ENDIANESS) \ |
-finput-charset=UTF-8 -fno-builtin -Wall -Wextra -Wno-unused-parameter \ |
-Wmissing-prototypes -Werror-implicit-function-declaration -nostdlib \ |
-nostdinc -pipe -g -D__$(ENDIANESS)__ |
-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32 -finput-charset=UTF-8 \ |
-fno-builtin -Wall -Wextra -Wno-unused-parameter -Wmissing-prototypes \ |
-Werror-implicit-function-declaration -nostdlib -nostdinc -pipe -g |
LFLAGS = -M -N $(SOFTINT_PREFIX)/libsoftint.a |
AFLAGS = |
/branches/dd/uspace/lib/libc/generic/malloc.c |
---|
File deleted |
/branches/dd/uspace/lib/libc/generic/errno.c |
---|
File deleted |
/branches/dd/uspace/lib/libc/generic/task.c |
---|
148,23 → 148,10 |
return 0; |
} |
int task_wait(task_id_t id, task_exit_t *texit, int *retval) |
int task_wait(task_id_t id) |
{ |
ipcarg_t te, rv; |
int rc; |
rc = (int) async_req_2_2(PHONE_NS, NS_TASK_WAIT, LOWER32(id), |
UPPER32(id), &te, &rv); |
*texit = te; |
*retval = rv; |
return rc; |
return (int) async_req_2_0(PHONE_NS, NS_TASK_WAIT, LOWER32(id), UPPER32(id)); |
} |
int task_retval(int val) |
{ |
return (int) async_req_1_0(PHONE_NS, NS_RETVAL, val); |
} |
/** @} |
*/ |
/branches/dd/uspace/lib/libc/generic/as.c |
---|
38,23 → 38,23 |
#include <align.h> |
#include <sys/types.h> |
#include <bitops.h> |
#include <malloc.h> |
/** Last position allocated by as_get_mappable_page */ |
static uintptr_t last_allocated = 0; |
/** |
* Either 4*256M on 32-bit architecures or 16*256M on 64-bit architectures. |
*/ |
#define MAX_HEAP_SIZE (sizeof(uintptr_t)<<28) |
/** Create address space area. |
* |
* @param address Virtual address where to place new address space area. |
* @param size Size of the area. |
* @param flags Flags describing type of the area. |
* @param size Size of the area. |
* @param flags Flags describing type of the area. |
* |
* @return address on success, (void *) -1 otherwise. |
* |
*/ |
void *as_area_create(void *address, size_t size, int flags) |
{ |
return (void *) __SYSCALL3(SYS_AS_AREA_CREATE, (sysarg_t) address, |
return (void *) __SYSCALL3(SYS_AS_AREA_CREATE, (sysarg_t ) address, |
(sysarg_t) size, (sysarg_t) flags); |
} |
61,16 → 61,15 |
/** Resize address space area. |
* |
* @param address Virtual address pointing into already existing address space |
* area. |
* @param size New requested size of the area. |
* @param flags Currently unused. |
* area. |
* @param size New requested size of the area. |
* @param flags Currently unused. |
* |
* @return zero on success or a code from @ref errno.h on failure. |
* |
* @return Zero on success or a code from @ref errno.h on failure. |
*/ |
int as_area_resize(void *address, size_t size, int flags) |
{ |
return __SYSCALL3(SYS_AS_AREA_RESIZE, (sysarg_t) address, |
return __SYSCALL3(SYS_AS_AREA_RESIZE, (sysarg_t ) address, |
(sysarg_t) size, (sysarg_t) flags); |
} |
77,24 → 76,22 |
/** Destroy address space area. |
* |
* @param address Virtual address pointing into the address space area being |
* destroyed. |
* destroyed. |
* |
* @return zero on success or a code from @ref errno.h on failure. |
* |
* @return Zero on success or a code from @ref errno.h on failure. |
*/ |
int as_area_destroy(void *address) |
{ |
return __SYSCALL1(SYS_AS_AREA_DESTROY, (sysarg_t) address); |
return __SYSCALL1(SYS_AS_AREA_DESTROY, (sysarg_t ) address); |
} |
/** Change address-space area flags. |
* |
* @param address Virtual address pointing into the address space area being |
* modified. |
* @param flags New flags describing type of the area. |
* modified. |
* @param flags New flags describing type of the area. |
* |
* @return zero on success or a code from @ref errno.h on failure. |
* |
* @return Zero on success or a code from @ref errno.h on failure. |
*/ |
int as_area_change_flags(void *address, int flags) |
{ |
102,29 → 99,101 |
(sysarg_t) flags); |
} |
static size_t heapsize = 0; |
static size_t maxheapsize = (size_t) (-1); |
static void *last_allocated = 0; |
/* Start of heap linker symbol */ |
extern char _heap; |
/** Sbrk emulation |
* |
* @param incr New area that should be allocated or negative, |
if it should be shrinked |
* @return Pointer to newly allocated area |
*/ |
void *sbrk(ssize_t incr) |
{ |
int rc; |
void *res; |
/* Check for invalid values */ |
if ((incr < 0) && (((size_t) -incr) > heapsize)) |
return NULL; |
/* Check for too large value */ |
if ((incr > 0) && (incr + heapsize < heapsize)) |
return NULL; |
/* Check for too small values */ |
if ((incr < 0) && (incr + heapsize > heapsize)) |
return NULL; |
/* Check for user limit */ |
if ((maxheapsize != (size_t) (-1)) && (heapsize + incr) > maxheapsize) |
return NULL; |
rc = as_area_resize(&_heap, heapsize + incr, 0); |
if (rc != 0) |
return NULL; |
/* Compute start of new area */ |
res = (void *) &_heap + heapsize; |
heapsize += incr; |
return res; |
} |
/** Set maximum heap size and return pointer just after the heap */ |
void *set_maxheapsize(size_t mhs) |
{ |
maxheapsize = mhs; |
/* Return pointer to area not managed by sbrk */ |
return ((void *) &_heap + maxheapsize); |
} |
/** Return pointer to some unmapped area, where fits new as_area |
* |
* @param size Requested size of the allocation. |
* @param sz Requested size of the allocation. |
* |
* @return pointer to the beginning |
* @return Pointer to the beginning |
* |
* TODO: make some first_fit/... algorithm, we are now just incrementing |
* the pointer to last area |
*/ |
void *as_get_mappable_page(size_t size) |
void *as_get_mappable_page(size_t sz) |
{ |
if (size == 0) |
return NULL; |
void *res; |
uint64_t asz; |
int i; |
size_t sz = 1 << (fnzb(size - 1) + 1); |
if (last_allocated == 0) |
last_allocated = get_max_heap_addr(); |
if (!sz) |
return NULL; |
asz = 1 << (fnzb64(sz - 1) + 1); |
/* Set heapsize to some meaningful value */ |
if (maxheapsize == (size_t) -1) |
set_maxheapsize(MAX_HEAP_SIZE); |
/* |
* Make sure we allocate from naturally aligned address. |
*/ |
uintptr_t res = ALIGN_UP(last_allocated, sz); |
last_allocated = res + ALIGN_UP(size, PAGE_SIZE); |
return ((void *) res); |
i = 0; |
if (!last_allocated) { |
last_allocated = (void *) ALIGN_UP((void *) &_heap + |
maxheapsize, asz); |
} else { |
last_allocated = (void *) ALIGN_UP(((uintptr_t) |
last_allocated) + (int) (i > 0), asz); |
} |
res = last_allocated; |
last_allocated += ALIGN_UP(sz, PAGE_SIZE); |
return res; |
} |
/** @} |
/branches/dd/uspace/lib/libc/generic/libc.c |
---|
52,8 → 52,11 |
#include <as.h> |
#include <loader/pcb.h> |
extern char _heap; |
extern int main(int argc, char *argv[]); |
int _errno; |
void _exit(int status) |
{ |
thread_exit(status); |
61,10 → 64,9 |
void __main(void *pcb_ptr) |
{ |
int retval; |
__heap_init(); |
__async_init(); |
(void) as_area_create(&_heap, 1, AS_AREA_WRITE | AS_AREA_READ); |
_async_init(); |
fibril_t *fibril = fibril_setup(); |
__tcb_set(fibril->tcb); |
77,17 → 79,15 |
if (__pcb == NULL) { |
argc = 0; |
argv = NULL; |
__stdio_init(0, NULL); |
stdio_init(0, NULL); |
} else { |
argc = __pcb->argc; |
argv = __pcb->argv; |
__stdio_init(__pcb->filc, __pcb->filv); |
stdio_init(__pcb->filc, __pcb->filv); |
} |
retval = main(argc, argv); |
__stdio_done(); |
(void) task_retval(retval); |
main(argc, argv); |
stdio_done(); |
} |
void __exit(void) |
/branches/dd/uspace/lib/libc/generic/devmap.c |
---|
193,7 → 193,7 |
if (retval != EOK) { |
if (handle != NULL) |
*handle = (dev_handle_t) -1; |
*handle = -1; |
return retval; |
} |
218,31 → 218,6 |
return phone; |
} |
int devmap_null_create(void) |
{ |
int phone = devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING); |
if (phone < 0) |
return -1; |
ipcarg_t null_id; |
int retval = async_req_0_1(phone, DEVMAP_DEVICE_NULL_CREATE, &null_id); |
if (retval != EOK) |
return -1; |
return (int) null_id; |
} |
void devmap_null_destroy(int null_id) |
{ |
int phone = devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING); |
if (phone < 0) |
return; |
async_req_1_0(phone, DEVMAP_DEVICE_NULL_DESTROY, (ipcarg_t) null_id); |
} |
ipcarg_t devmap_device_get_count(void) |
{ |
int phone = devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING); |
/branches/dd/uspace/lib/libc/generic/async.c |
---|
178,6 → 178,7 |
static void default_client_connection(ipc_callid_t callid, ipc_call_t *call); |
static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call); |
static void default_pending(void); |
/** |
* Pointer to a fibril function that will be used to handle connections. |
190,6 → 191,12 |
*/ |
static async_client_conn_t interrupt_received = default_interrupt_received; |
/** |
* Pointer to a fibril function that will be used to handle pending |
* operations. |
*/ |
static async_pending_t pending = default_pending; |
static hash_table_t conn_hash_table; |
static LIST_INITIALIZE(timeout_list); |
374,6 → 381,42 |
return true; |
} |
/** Pending fibril. |
* |
* After each call the pending operations are executed in a separate |
* fibril. The function pending() is c. |
* |
* @param arg Unused. |
* |
* @return Always zero. |
* |
*/ |
static int pending_fibril(void *arg) |
{ |
pending(); |
return 0; |
} |
/** Process pending actions. |
* |
* A new fibril is created which would process the pending operations. |
* |
* @return False if an error occured. |
* True if the execution was passed to the pending fibril. |
* |
*/ |
static bool process_pending(void) |
{ |
futex_down(&async_futex); |
fid_t fid = fibril_create(pending_fibril, NULL); |
fibril_add_ready(fid); |
futex_up(&async_futex); |
return true; |
} |
/** Return new incoming message for the current (fibril-local) connection. |
* |
* @param call Storage where the incoming call data will be stored. |
470,6 → 513,15 |
{ |
} |
/** Default fibril function that gets called to handle pending operations. |
* |
* This function is defined as a weak symbol - to be redefined in user code. |
* |
*/ |
static void default_pending(void) |
{ |
} |
/** Wrapper for client connection fibril. |
* |
* When a new connection arrives, a fibril with this implementing function is |
608,7 → 660,7 |
return; |
out: |
; |
process_pending(); |
} |
/** Fire all timeouts that expired. */ |
738,7 → 790,7 |
* |
* @return Zero on success or an error code. |
*/ |
int __async_init(void) |
int _async_init(void) |
{ |
if (!hash_table_create(&conn_hash_table, CONN_HASH_TABLE_CHAINS, 1, |
&conn_hash_table_ops)) { |
997,6 → 1049,16 |
interrupt_received = intr; |
} |
/** Setter for pending function pointer. |
* |
* @param pend Function that will implement a new pending |
* operations fibril. |
*/ |
void async_set_pending(async_pending_t pend) |
{ |
pending = pend; |
} |
/** Pseudo-synchronous message sending - fast version. |
* |
* Send message asynchronously and return only after the reply arrives. |
/branches/dd/uspace/lib/libc/generic/vfs/vfs.c |
---|
38,8 → 38,8 |
#include <unistd.h> |
#include <dirent.h> |
#include <fcntl.h> |
#include <sys/stat.h> |
#include <stdio.h> |
#include <sys/stat.h> |
#include <sys/types.h> |
#include <ipc/ipc.h> |
#include <ipc/services.h> |
137,7 → 137,7 |
async_serialize_start(); |
vfs_connect(); |
req = async_send_2(vfs_phone, VFS_IN_MOUNT, dev_handle, flags, NULL); |
req = async_send_2(vfs_phone, VFS_MOUNT, dev_handle, flags, NULL); |
rc = ipc_data_write_start(vfs_phone, (void *) mpa, mpa_size); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
198,7 → 198,7 |
async_serialize_start(); |
vfs_connect(); |
req = async_send_3(vfs_phone, VFS_IN_OPEN, lflag, oflag, 0, &answer); |
req = async_send_3(vfs_phone, VFS_OPEN, lflag, oflag, 0, &answer); |
rc = ipc_data_write_start(vfs_phone, pa, pa_size); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
230,7 → 230,7 |
vfs_connect(); |
ipc_call_t answer; |
aid_t req = async_send_4(vfs_phone, VFS_IN_OPEN_NODE, node->fs_handle, |
aid_t req = async_send_4(vfs_phone, VFS_OPEN_NODE, node->fs_handle, |
node->dev_handle, node->index, oflag, &answer); |
ipcarg_t rc; |
252,7 → 252,7 |
async_serialize_start(); |
vfs_connect(); |
rc = async_req_1_0(vfs_phone, VFS_IN_CLOSE, fildes); |
rc = async_req_1_0(vfs_phone, VFS_CLOSE, fildes); |
async_serialize_end(); |
futex_up(&vfs_phone_futex); |
270,7 → 270,7 |
async_serialize_start(); |
vfs_connect(); |
req = async_send_1(vfs_phone, VFS_IN_READ, fildes, &answer); |
req = async_send_1(vfs_phone, VFS_READ, fildes, &answer); |
rc = ipc_data_read_start(vfs_phone, (void *)buf, nbyte); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
297,7 → 297,7 |
async_serialize_start(); |
vfs_connect(); |
req = async_send_1(vfs_phone, VFS_IN_WRITE, fildes, &answer); |
req = async_send_1(vfs_phone, VFS_WRITE, fildes, &answer); |
rc = ipc_data_write_start(vfs_phone, (void *)buf, nbyte); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
314,116 → 314,95 |
return -1; |
} |
int fsync(int fildes) |
int fd_phone(int fildes) |
{ |
futex_down(&vfs_phone_futex); |
async_serialize_start(); |
vfs_connect(); |
ipcarg_t rc = async_req_1_0(vfs_phone, VFS_IN_SYNC, fildes); |
ipcarg_t device; |
ipcarg_t rc = async_req_1_1(vfs_phone, VFS_DEVICE, fildes, &device); |
async_serialize_end(); |
futex_up(&vfs_phone_futex); |
return (int) rc; |
if (rc != EOK) |
return -1; |
return devmap_device_connect((dev_handle_t) device, 0); |
} |
off_t lseek(int fildes, off_t offset, int whence) |
int fd_node(int fildes, fdi_node_t *node) |
{ |
ipcarg_t rc; |
futex_down(&vfs_phone_futex); |
async_serialize_start(); |
vfs_connect(); |
ipcarg_t newoffs; |
rc = async_req_3_1(vfs_phone, VFS_IN_SEEK, fildes, offset, whence, |
&newoffs); |
ipcarg_t fs_handle; |
ipcarg_t dev_handle; |
ipcarg_t index; |
ipcarg_t rc = async_req_1_3(vfs_phone, VFS_NODE, fildes, &fs_handle, |
&dev_handle, &index); |
async_serialize_end(); |
futex_up(&vfs_phone_futex); |
if (rc != EOK) |
return (off_t) -1; |
return (off_t) newoffs; |
if (rc == EOK) { |
node->fs_handle = (fs_handle_t) fs_handle; |
node->dev_handle = (dev_handle_t) dev_handle; |
node->index = (fs_index_t) index; |
} |
return rc; |
} |
int ftruncate(int fildes, off_t length) |
int fsync(int fildes) |
{ |
ipcarg_t rc; |
futex_down(&vfs_phone_futex); |
async_serialize_start(); |
vfs_connect(); |
rc = async_req_2_0(vfs_phone, VFS_IN_TRUNCATE, fildes, length); |
ipcarg_t rc = async_req_1_0(vfs_phone, VFS_SYNC, fildes); |
async_serialize_end(); |
futex_up(&vfs_phone_futex); |
return (int) rc; |
} |
int fstat(int fildes, struct stat *stat) |
off_t lseek(int fildes, off_t offset, int whence) |
{ |
ipcarg_t rc; |
ipc_call_t answer; |
aid_t req; |
futex_down(&vfs_phone_futex); |
async_serialize_start(); |
vfs_connect(); |
req = async_send_1(vfs_phone, VFS_IN_FSTAT, fildes, NULL); |
rc = ipc_data_read_start(vfs_phone, (void *)stat, sizeof(struct stat)); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
async_serialize_end(); |
futex_up(&vfs_phone_futex); |
return (ssize_t) rc; |
} |
async_wait_for(req, &rc); |
ipcarg_t newoffs; |
rc = async_req_3_1(vfs_phone, VFS_SEEK, fildes, offset, whence, |
&newoffs); |
async_serialize_end(); |
futex_up(&vfs_phone_futex); |
return rc; |
if (rc != EOK) |
return (off_t) -1; |
return (off_t) newoffs; |
} |
int stat(const char *path, struct stat *stat) |
int ftruncate(int fildes, off_t length) |
{ |
ipcarg_t rc; |
aid_t req; |
size_t pa_size; |
char *pa = absolutize(path, &pa_size); |
if (!pa) |
return ENOMEM; |
futex_down(&vfs_phone_futex); |
async_serialize_start(); |
vfs_connect(); |
req = async_send_0(vfs_phone, VFS_IN_STAT, NULL); |
rc = ipc_data_write_start(vfs_phone, pa, pa_size); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
async_serialize_end(); |
futex_up(&vfs_phone_futex); |
free(pa); |
return (int) rc; |
} |
rc = ipc_data_read_start(vfs_phone, stat, sizeof(struct stat)); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
async_serialize_end(); |
futex_up(&vfs_phone_futex); |
free(pa); |
return (int) rc; |
} |
async_wait_for(req, &rc); |
rc = async_req_2_0(vfs_phone, VFS_TRUNCATE, fildes, length); |
async_serialize_end(); |
futex_up(&vfs_phone_futex); |
free(pa); |
return rc; |
return (int) rc; |
} |
DIR *opendir(const char *dirname) |
473,7 → 452,7 |
async_serialize_start(); |
vfs_connect(); |
req = async_send_1(vfs_phone, VFS_IN_MKDIR, mode, NULL); |
req = async_send_1(vfs_phone, VFS_MKDIR, mode, NULL); |
rc = ipc_data_write_start(vfs_phone, pa, pa_size); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
503,7 → 482,7 |
async_serialize_start(); |
vfs_connect(); |
req = async_send_0(vfs_phone, VFS_IN_UNLINK, NULL); |
req = async_send_0(vfs_phone, VFS_UNLINK, NULL); |
rc = ipc_data_write_start(vfs_phone, pa, pa_size); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
550,7 → 529,7 |
async_serialize_start(); |
vfs_connect(); |
req = async_send_0(vfs_phone, VFS_IN_RENAME, NULL); |
req = async_send_0(vfs_phone, VFS_RENAME, NULL); |
rc = ipc_data_write_start(vfs_phone, olda, olda_size); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
619,34 → 598,5 |
return buf; |
} |
int fd_phone(int fildes) |
{ |
struct stat stat; |
int rc; |
rc = fstat(fildes, &stat); |
if (!stat.devfs_stat.device) |
return -1; |
return devmap_device_connect(stat.devfs_stat.device, 0); |
} |
int fd_node(int fildes, fdi_node_t *node) |
{ |
struct stat stat; |
int rc; |
rc = fstat(fildes, &stat); |
if (rc == EOK) { |
node->fs_handle = stat.fs_handle; |
node->dev_handle = stat.dev_handle; |
node->index = stat.index; |
} |
return rc; |
} |
/** @} |
*/ |
/branches/dd/uspace/lib/libc/generic/io/console.c |
---|
69,17 → 69,6 |
async_msg_1(phone, CONSOLE_CURSOR_VISIBILITY, show != false); |
} |
int console_get_color_cap(int phone, int *ccap) |
{ |
ipcarg_t ccap_tmp; |
int rc; |
rc = async_req_0_1(phone, CONSOLE_GET_COLOR_CAP, &ccap_tmp); |
*ccap = ccap_tmp; |
return rc; |
} |
void console_kcon_enable(int phone) |
{ |
async_msg_0(phone, CONSOLE_KCON_ENABLE); |
/branches/dd/uspace/lib/libc/generic/io/io.c |
---|
35,7 → 35,6 |
#include <stdio.h> |
#include <unistd.h> |
#include <fcntl.h> |
#include <assert.h> |
#include <string.h> |
#include <errno.h> |
#include <bool.h> |
45,18 → 44,12 |
#include <ipc/devmap.h> |
#include <adt/list.h> |
static void _fflushbuf(FILE *stream); |
static FILE stdin_null = { |
.fd = -1, |
.error = true, |
.eof = true, |
.klog = false, |
.phone = -1, |
.btype = _IONBF, |
.buf = NULL, |
.buf_size = 0, |
.buf_head = NULL |
.phone = -1 |
}; |
static FILE stdout_klog = { |
64,11 → 57,7 |
.error = false, |
.eof = false, |
.klog = true, |
.phone = -1, |
.btype = _IOLBF, |
.buf = NULL, |
.buf_size = BUFSIZ, |
.buf_head = NULL |
.phone = -1 |
}; |
static FILE stderr_klog = { |
76,11 → 65,7 |
.error = false, |
.eof = false, |
.klog = true, |
.phone = -1, |
.btype = _IONBF, |
.buf = NULL, |
.buf_size = 0, |
.buf_head = NULL |
.phone = -1 |
}; |
FILE *stdin = NULL; |
89,7 → 74,7 |
static LIST_INITIALIZE(files); |
void __stdio_init(int filc, fdi_node_t *filv[]) |
void stdio_init(int filc, fdi_node_t *filv[]) |
{ |
if (filc > 0) { |
stdin = fopen_node(filv[0], "r"); |
113,7 → 98,7 |
} |
} |
void __stdio_done(void) |
void stdio_done(void) |
{ |
link_t *link = files.next; |
171,47 → 156,6 |
return true; |
} |
/** Set stream buffer. */ |
void setvbuf(FILE *stream, void *buf, int mode, size_t size) |
{ |
stream->btype = mode; |
stream->buf = buf; |
stream->buf_size = size; |
stream->buf_head = stream->buf; |
} |
static void _setvbuf(FILE *stream) |
{ |
/* FIXME: Use more complex rules for setting buffering options. */ |
switch (stream->fd) { |
case 1: |
setvbuf(stream, NULL, _IOLBF, BUFSIZ); |
break; |
case 0: |
case 2: |
setvbuf(stream, NULL, _IONBF, 0); |
break; |
default: |
setvbuf(stream, NULL, _IOFBF, BUFSIZ); |
} |
} |
/** Allocate stream buffer. */ |
static int _fallocbuf(FILE *stream) |
{ |
assert(stream->buf == NULL); |
stream->buf = malloc(stream->buf_size); |
if (stream->buf == NULL) { |
errno = ENOMEM; |
return -1; |
} |
stream->buf_head = stream->buf; |
return 0; |
} |
/** Open a stream. |
* |
* @param path Path of the file to open. |
242,7 → 186,6 |
stream->eof = false; |
stream->klog = false; |
stream->phone = -1; |
_setvbuf(stream); |
list_append(&stream->link, &files); |
263,7 → 206,6 |
stream->eof = false; |
stream->klog = false; |
stream->phone = -1; |
_setvbuf(stream); |
list_append(&stream->link, &files); |
294,7 → 236,6 |
stream->eof = false; |
stream->klog = false; |
stream->phone = -1; |
_setvbuf(stream); |
list_append(&stream->link, &files); |
343,9 → 284,6 |
size_t left = size * nmemb; |
size_t done = 0; |
/* Make sure no data is pending write. */ |
_fflushbuf(stream); |
while ((left > 0) && (!stream->error) && (!stream->eof)) { |
ssize_t rd = read(stream->fd, buf + done, left); |
362,7 → 300,15 |
return (done / size); |
} |
static size_t _fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream) |
/** Write to a stream. |
* |
* @param buf Source buffer. |
* @param size Size of each record. |
* @param nmemb Number of records to write. |
* @param stream Pointer to the stream. |
* |
*/ |
size_t fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream) |
{ |
size_t left = size * nmemb; |
size_t done = 0; |
386,93 → 332,6 |
return (done / size); |
} |
/** Drain stream buffer, do not sync stream. */ |
static void _fflushbuf(FILE *stream) |
{ |
size_t bytes_used; |
if ((!stream->buf) || (stream->btype == _IONBF) || (stream->error)) |
return; |
bytes_used = stream->buf_head - stream->buf; |
if (bytes_used == 0) |
return; |
(void) _fwrite(stream->buf, 1, bytes_used, stream); |
stream->buf_head = stream->buf; |
} |
/** Write to a stream. |
* |
* @param buf Source buffer. |
* @param size Size of each record. |
* @param nmemb Number of records to write. |
* @param stream Pointer to the stream. |
* |
*/ |
size_t fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream) |
{ |
uint8_t *data; |
size_t bytes_left; |
size_t now; |
size_t buf_free; |
size_t total_written; |
size_t i; |
uint8_t b; |
bool need_flush; |
/* If not buffered stream, write out directly. */ |
if (stream->btype == _IONBF) { |
now = _fwrite(buf, size, nmemb, stream); |
fflush(stream); |
return now; |
} |
/* Perform lazy allocation of stream buffer. */ |
if (stream->buf == NULL) { |
if (_fallocbuf(stream) != 0) |
return 0; /* Errno set by _fallocbuf(). */ |
} |
data = (uint8_t *) buf; |
bytes_left = size * nmemb; |
total_written = 0; |
need_flush = false; |
while ((!stream->error) && (bytes_left > 0)) { |
buf_free = stream->buf_size - (stream->buf_head - stream->buf); |
if (bytes_left > buf_free) |
now = buf_free; |
else |
now = bytes_left; |
for (i = 0; i < now; i++) { |
b = data[i]; |
stream->buf_head[i] = b; |
if ((b == '\n') && (stream->btype == _IOLBF)) |
need_flush = true; |
} |
buf += now; |
stream->buf_head += now; |
buf_free -= now; |
bytes_left -= now; |
total_written += now; |
if (buf_free == 0) { |
/* Only need to drain buffer. */ |
_fflushbuf(stream); |
need_flush = false; |
} |
} |
if (need_flush) |
fflush(stream); |
return (total_written / size); |
} |
int fputc(wchar_t c, FILE *stream) |
{ |
char buf[STR_BOUNDS(1)]; |
508,13 → 367,13 |
int fgetc(FILE *stream) |
{ |
char c; |
/* This could be made faster by only flushing when needed. */ |
if (stdout) |
fflush(stdout); |
if (stderr) |
fflush(stderr); |
if (fread(&c, sizeof(char), 1, stream) < sizeof(char)) |
return EOF; |
546,8 → 405,6 |
int fflush(FILE *stream) |
{ |
_fflushbuf(stream); |
if (stream->klog) { |
klog_update(); |
return EOK; |
/branches/dd/uspace/lib/libc/generic/io/printf_core.c |
---|
301,6 → 301,9 |
if (str == NULL) |
return printf_putstr(nullstr, ps); |
if (*str == U_BOM) |
str++; |
/* Print leading spaces. */ |
size_t strw = wstr_length(str); |
if (precision == 0) |
/branches/dd/uspace/lib/libc/generic/getopt.c |
---|
47,7 → 47,7 |
int optind = 1; /* index into parent argv vector */ |
int optopt = '?'; /* character checked for validity */ |
int optreset; /* reset getopt */ |
const char *optarg; /* argument associated with option */ |
char *optarg; /* argument associated with option */ |
#define IGNORE_FIRST (*options == '-' || *options == '+') |
162,7 → 162,7 |
char **nargv; |
const char *options; |
{ |
const char *oli; /* option letter list index */ |
char *oli; /* option letter list index */ |
int optchar; |
assert(nargv != NULL); |
275,7 → 275,7 |
} else { /* takes (optional) argument */ |
optarg = NULL; |
if (*place) /* no white space */ |
optarg = place; |
optarg = *place; |
/* XXX: disable test for :: if PC? (GNU doesn't) */ |
else if (oli[1] != ':') { /* arg not optional */ |
if (++optind >= nargc) { /* no arg */ |
353,8 → 353,7 |
retval = getopt_internal(nargc, (char **)nargv, options); |
if (retval == -2) { |
char *current_argv; |
const char *has_equal; |
char *current_argv, *has_equal; |
size_t current_argv_len; |
int i, ambiguous, match; |
/branches/dd/uspace/lib/libc/generic/mman.c |
---|
37,18 → 37,17 |
#include <as.h> |
#include <unistd.h> |
void *mmap(void *start, size_t length, int prot, int flags, int fd, |
void *mmap(void *start, size_t length, int prot, int flags, int fd, |
off_t offset) |
{ |
if (!start) |
start = as_get_mappable_page(length); |
// if (!((flags & MAP_SHARED) ^ (flags & MAP_PRIVATE))) |
// if (! ((flags & MAP_SHARED) ^ (flags & MAP_PRIVATE))) |
// return MAP_FAILED; |
if (!(flags & MAP_ANONYMOUS)) |
if (! (flags & MAP_ANONYMOUS)) |
return MAP_FAILED; |
return as_area_create(start, length, prot); |
} |
/branches/dd/uspace/lib/libc/Makefile |
---|
32,7 → 32,6 |
LIBC_PREFIX = $(shell pwd) |
SOFTINT_PREFIX = ../softint |
## Setup toolchain |
# |
49,7 → 48,6 |
generic/cap.c \ |
generic/devmap.c \ |
generic/event.c \ |
generic/errno.c \ |
generic/mem.c \ |
generic/string.c \ |
generic/fibril.c \ |
69,7 → 67,7 |
generic/io/vsnprintf.c \ |
generic/io/printf_core.c \ |
generic/io/console.c \ |
generic/malloc.c \ |
malloc/malloc.c \ |
generic/sysinfo.c \ |
generic/ipc.c \ |
generic/async.c \ |
106,7 → 104,7 |
clean: |
-rm -f include/kernel include/arch include/libarch libc.a arch/$(UARCH)/_link.ld Makefile.depend |
find generic/ arch/$(UARCH)/ -name '*.o' -follow -exec rm \{\} \; |
find generic/ arch/$(UARCH)/ malloc -name '*.o' -follow -exec rm \{\} \; |
depend: kerninc |
-makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(ARCH_SOURCES) $(GENERIC_SOURCES) > Makefile.depend 2> /dev/null |
/branches/dd/uspace/lib/libc/arch/sparc64/include/byteorder.h |
---|
0,0 → 1,43 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup libcsparc64 |
* @{ |
*/ |
/** @file |
*/ |
#ifndef LIBC_sparc64_BYTEORDER_H_ |
#define LIBC_sparc64_BYTEORDER_H_ |
#define ARCH_IS_BIG_ENDIAN |
#endif |
/** @} |
*/ |
/branches/dd/uspace/lib/libc/arch/sparc64/include/fibril.h |
---|
39,7 → 39,7 |
#include <sys/types.h> |
#include <align.h> |
#define SP_DELTA (STACK_WINDOW_SAVE_AREA_SIZE + STACK_ARG_SAVE_AREA_SIZE) |
#define SP_DELTA STACK_WINDOW_SAVE_AREA_SIZE |
#ifdef context_set |
#undef context_set |
/branches/dd/uspace/lib/libc/arch/sparc64/include/stack.h |
---|
45,11 → 45,6 |
*/ |
#define STACK_WINDOW_SAVE_AREA_SIZE (16 * STACK_ITEM_SIZE) |
/* |
* Six extended words for first six arguments. |
*/ |
#define STACK_ARG_SAVE_AREA_SIZE (6 * STACK_ITEM_SIZE) |
/** |
* By convention, the actual top of the stack is %sp + STACK_BIAS. |
*/ |
/branches/dd/uspace/lib/libc/arch/sparc64/Makefile.inc |
---|
38,7 → 38,5 |
CFLAGS += -mcpu=ultrasparc -m64 |
LFLAGS += -no-check-sections -N |
ENDIANESS = BE |
BFD_NAME = elf64-sparc |
BFD_ARCH = sparc |
/branches/dd/uspace/lib/libc/arch/ia64/include/byteorder.h |
---|
0,0 → 1,44 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup libcia64 |
* @{ |
*/ |
/** @file |
*/ |
#ifndef LIBC_ia64_BYTEORDER_H_ |
#define LIBC_ia64_BYTEORDER_H_ |
/* IA-64 is little-endian */ |
#define ARCH_IS_LITTLE_ENDIAN |
#endif |
/** @} |
*/ |
/branches/dd/uspace/lib/libc/arch/ia64/Makefile.inc |
---|
31,6 → 31,9 |
TARGET = ia64-pc-linux-gnu |
TOOLCHAIN_DIR = $(CROSS_PREFIX)/ia64/bin |
CFLAGS += -fno-unwind-tables -DMALLOC_ALIGNMENT_16 |
LFLAGS += -N $(SOFTINT_PREFIX)/libsoftint.a |
AFLAGS += |
ARCH_SOURCES += arch/$(UARCH)/src/syscall.S \ |
arch/$(UARCH)/src/fibril.S \ |
37,10 → 40,5 |
arch/$(UARCH)/src/tls.c \ |
arch/$(UARCH)/src/ddi.c |
CFLAGS += -fno-unwind-tables |
LFLAGS += -N $(SOFTINT_PREFIX)/libsoftint.a |
ENDIANESS = LE |
BFD_NAME = elf64-ia64-little |
BFD_ARCH = ia64-elf64 |
/branches/dd/uspace/lib/libc/arch/arm32/include/byteorder.h |
---|
0,0 → 1,44 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup libcarm32 |
* @{ |
*/ |
/** @file |
* @brief Endianness definitions. |
*/ |
#ifndef LIBC_arm32_BYTEORDER_H_ |
#define LIBC_arm32_BYTEORDER_H_ |
#define ARCH_IS_LITTLE_ENDIAN |
#endif |
/** @} |
*/ |
/branches/dd/uspace/lib/libc/arch/arm32/Makefile.inc |
---|
32,6 → 32,9 |
TARGET = arm-linux-gnu |
TOOLCHAIN_DIR = $(CROSS_PREFIX)/arm/bin |
CFLAGS += -ffixed-r9 -mtp=soft |
LFLAGS += -N $(SOFTINT_PREFIX)/libsoftint.a |
AFLAGS += |
ARCH_SOURCES += arch/$(UARCH)/src/syscall.c \ |
arch/$(UARCH)/src/fibril.S \ |
38,10 → 41,5 |
arch/$(UARCH)/src/tls.c \ |
arch/$(UARCH)/src/eabi.S |
CFLAGS += -ffixed-r9 -mtp=soft |
LFLAGS += -N $(SOFTINT_PREFIX)/libsoftint.a |
ENDIANESS = LE |
BFD_NAME = elf32-littlearm |
BFD_ARCH = arm |
/branches/dd/uspace/lib/libc/arch/ppc32/include/byteorder.h |
---|
0,0 → 1,43 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup libcppc32 |
* @{ |
*/ |
/** @file |
*/ |
#ifndef LIBC_ppc32_BYTEORDER_H_ |
#define LIBC_ppc32_BYTEORDER_H_ |
#define ARCH_IS_BIG_ENDIAN |
#endif |
/** @} |
*/ |
/branches/dd/uspace/lib/libc/arch/ppc32/Makefile.inc |
---|
40,7 → 40,5 |
AFLAGS += -a32 |
LFLAGS += -N |
ENDIANESS = BE |
BFD_NAME = elf32-powerpc |
BFD_ARCH = powerpc:common |
/branches/dd/uspace/lib/libc/arch/amd64/include/byteorder.h |
---|
0,0 → 1,44 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup libcamd64 |
* @{ |
*/ |
/** @file |
*/ |
#ifndef LIBC_amd64_BYTEORDER_H_ |
#define LIBC_amd64_BYTEORDER_H_ |
/* AMD64 is little-endian */ |
#define ARCH_IS_LITTLE_ENDIAN |
#endif |
/** @} |
*/ |
/branches/dd/uspace/lib/libc/arch/amd64/Makefile.inc |
---|
38,7 → 38,5 |
LFLAGS += -N |
ENDIANESS = LE |
BFD_NAME = elf64-x86-64 |
BFD_ARCH = i386:x86-64 |
/branches/dd/uspace/lib/libc/arch/mips32/include/byteorder.h |
---|
0,0 → 1,43 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup libcmips32 |
* @{ |
*/ |
/** @file |
*/ |
#ifndef LIBC_mips32_BYTEORDER_H_ |
#define LIBC_mips32_BYTEORDER_H_ |
#define ARCH_IS_LITTLE_ENDIAN |
#endif |
/** @} |
*/ |
/branches/dd/uspace/lib/libc/arch/mips32/Makefile.inc |
---|
31,14 → 31,11 |
TARGET = mipsel-linux-gnu |
TOOLCHAIN_DIR = $(CROSS_PREFIX)/mipsel/bin |
CFLAGS += -mips3 |
ARCH_SOURCES += arch/$(UARCH)/src/syscall.c \ |
arch/$(UARCH)/src/fibril.S \ |
arch/$(UARCH)/src/tls.c |
CFLAGS += -mips3 |
ENDIANESS = LE |
BFD_ARCH = mips |
BFD_NAME = elf32-tradlittlemips |
/branches/dd/uspace/lib/libc/arch/ia32/include/byteorder.h |
---|
0,0 → 1,44 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup libcia32 |
* @{ |
*/ |
/** @file |
*/ |
#ifndef LIBC_ia32_BYTEORDER_H_ |
#define LIBC_ia32_BYTEORDER_H_ |
/* IA-32 is little-endian */ |
#define ARCH_IS_LITTLE_ENDIAN |
#endif |
/** @} |
*/ |
/branches/dd/uspace/lib/libc/arch/ia32/Makefile.inc |
---|
39,7 → 39,5 |
LFLAGS += -N |
ENDIANESS = LE |
BFD_NAME = elf32-i386 |
BFD_ARCH = i386 |
/branches/dd/uspace/lib/libc/arch/mips32eb/include/byteorder.h |
---|
0,0 → 1,43 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup libcmips32 |
* @{ |
*/ |
/** @file |
*/ |
#ifndef LIBC_mips32eb_BYTEORDER_H_ |
#define LIBC_mips32eb_BYTEORDER_H_ |
#define ARCH_IS_BIG_ENDIAN |
#endif |
/** @} |
*/ |
/branches/dd/uspace/lib/libc/arch/mips32eb/Makefile.inc |
---|
31,15 → 31,13 |
TARGET = mips-linux-gnu |
TOOLCHAIN_DIR = $(CROSS_PREFIX)/mips/bin |
CFLAGS += -mips3 |
ARCH_SOURCES += arch/$(UARCH)/src/syscall.c \ |
arch/$(UARCH)/src/fibril.S \ |
arch/$(UARCH)/src/tls.c |
CFLAGS += -mips3 |
LFLAGS += -N |
ENDIANESS = BE |
BFD_ARCH = mips |
BFD_NAME = elf32-tradbigmips |
/branches/dd/uspace/lib/libc/malloc/malloc.c |
---|
0,0 → 1,4431 |
#include <stdio.h> |
#include <libc.h> |
/* |
This is a version (aka dlmalloc) of malloc/free/realloc written by |
Doug Lea and released to the public domain, as explained at |
http://creativecommons.org/licenses/publicdomain. Send questions, |
comments, complaints, performance data, etc to dl@cs.oswego.edu |
* Version 2.8.3 Thu Sep 22 11:16:15 2005 Doug Lea (dl at gee) |
Note: There may be an updated version of this malloc obtainable at |
ftp://gee.cs.oswego.edu/pub/misc/malloc.c |
Check before installing! |
* Quickstart |
This library is all in one file to simplify the most common usage: |
ftp it, compile it (-O3), and link it into another program. All of |
the compile-time options default to reasonable values for use on |
most platforms. You might later want to step through various |
compile-time and dynamic tuning options. |
For convenience, an include file for code using this malloc is at: |
ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.3.h |
You don't really need this .h file unless you call functions not |
defined in your system include files. The .h file contains only the |
excerpts from this file needed for using this malloc on ANSI C/C++ |
systems, so long as you haven't changed compile-time options about |
naming and tuning parameters. If you do, then you can create your |
own malloc.h that does include all settings by cutting at the point |
indicated below. Note that you may already by default be using a C |
library containing a malloc that is based on some version of this |
malloc (for example in linux). You might still want to use the one |
in this file to customize settings or to avoid overheads associated |
with library versions. |
* Vital statistics: |
Supported pointer/size_t representation: 4 or 8 bytes |
size_t MUST be an unsigned type of the same width as |
pointers. (If you are using an ancient system that declares |
size_t as a signed type, or need it to be a different width |
than pointers, you can use a previous release of this malloc |
(e.g. 2.7.2) supporting these.) |
Alignment: 8 bytes (default) |
This suffices for nearly all current machines and C compilers. |
However, you can define MALLOC_ALIGNMENT to be wider than this |
if necessary (up to 128bytes), at the expense of using more space. |
Minimum overhead per allocated chunk: 4 or 8 bytes (if 4byte sizes) |
8 or 16 bytes (if 8byte sizes) |
Each malloced chunk has a hidden word of overhead holding size |
and status information, and additional cross-check word |
if FOOTERS is defined. |
Minimum allocated size: 4-byte ptrs: 16 bytes (including overhead) |
8-byte ptrs: 32 bytes (including overhead) |
Even a request for zero bytes (i.e., malloc(0)) returns a |
pointer to something of the minimum allocatable size. |
The maximum overhead wastage (i.e., number of extra bytes |
allocated than were requested in malloc) is less than or equal |
to the minimum size, except for requests >= mmap_threshold that |
are serviced via mmap(), where the worst case wastage is about |
32 bytes plus the remainder from a system page (the minimal |
mmap unit); typically 4096 or 8192 bytes. |
Security: static-safe; optionally more or less |
The "security" of malloc refers to the ability of malicious |
code to accentuate the effects of errors (for example, freeing |
space that is not currently malloc'ed or overwriting past the |
ends of chunks) in code that calls malloc. This malloc |
guarantees not to modify any memory locations below the base of |
heap, i.e., static variables, even in the presence of usage |
errors. The routines additionally detect most improper frees |
and reallocs. All this holds as long as the static bookkeeping |
for malloc itself is not corrupted by some other means. This |
is only one aspect of security -- these checks do not, and |
cannot, detect all possible programming errors. |
If FOOTERS is defined nonzero, then each allocated chunk |
carries an additional check word to verify that it was malloced |
from its space. These check words are the same within each |
execution of a program using malloc, but differ across |
executions, so externally crafted fake chunks cannot be |
freed. This improves security by rejecting frees/reallocs that |
could corrupt heap memory, in addition to the checks preventing |
writes to statics that are always on. This may further improve |
security at the expense of time and space overhead. (Note that |
FOOTERS may also be worth using with MSPACES.) |
By default detected errors cause the program to abort (calling |
"abort()"). You can override this to instead proceed past |
errors by defining PROCEED_ON_ERROR. In this case, a bad free |
has no effect, and a malloc that encounters a bad address |
caused by user overwrites will ignore the bad address by |
dropping pointers and indices to all known memory. This may |
be appropriate for programs that should continue if at all |
possible in the face of programming errors, although they may |
run out of memory because dropped memory is never reclaimed. |
If you don't like either of these options, you can define |
CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything |
else. And if if you are sure that your program using malloc has |
no errors or vulnerabilities, you can define INSECURE to 1, |
which might (or might not) provide a small performance improvement. |
Thread-safety: NOT thread-safe unless USE_LOCKS defined |
When USE_LOCKS is defined, each public call to malloc, free, |
etc is surrounded with either a pthread mutex or a win32 |
spinlock (depending on WIN32). This is not especially fast, and |
can be a major bottleneck. It is designed only to provide |
minimal protection in concurrent environments, and to provide a |
basis for extensions. If you are using malloc in a concurrent |
program, consider instead using ptmalloc, which is derived from |
a version of this malloc. (See http://www.malloc.de). |
System requirements: Any combination of MORECORE and/or MMAP/MUNMAP |
This malloc can use unix sbrk or any emulation (invoked using |
the CALL_MORECORE macro) and/or mmap/munmap or any emulation |
(invoked using CALL_MMAP/CALL_MUNMAP) to get and release system |
memory. On most unix systems, it tends to work best if both |
MORECORE and MMAP are enabled. On Win32, it uses emulations |
based on VirtualAlloc. It also uses common C library functions |
like memset. |
Compliance: I believe it is compliant with the Single Unix Specification |
(See http://www.unix.org). Also SVID/XPG, ANSI C, and probably |
others as well. |
* Overview of algorithms |
This is not the fastest, most space-conserving, most portable, or |
most tunable malloc ever written. However it is among the fastest |
while also being among the most space-conserving, portable and |
tunable. Consistent balance across these factors results in a good |
general-purpose allocator for malloc-intensive programs. |
In most ways, this malloc is a best-fit allocator. Generally, it |
chooses the best-fitting existing chunk for a request, with ties |
broken in approximately least-recently-used order. (This strategy |
normally maintains low fragmentation.) However, for requests less |
than 256bytes, it deviates from best-fit when there is not an |
exactly fitting available chunk by preferring to use space adjacent |
to that used for the previous small request, as well as by breaking |
ties in approximately most-recently-used order. (These enhance |
locality of series of small allocations.) And for very large requests |
(>= 256Kb by default), it relies on system memory mapping |
facilities, if supported. (This helps avoid carrying around and |
possibly fragmenting memory used only for large chunks.) |
All operations (except malloc_stats and mallinfo) have execution |
times that are bounded by a constant factor of the number of bits in |
a size_t, not counting any clearing in calloc or copying in realloc, |
or actions surrounding MORECORE and MMAP that have times |
proportional to the number of non-contiguous regions returned by |
system allocation routines, which is often just 1. |
The implementation is not very modular and seriously overuses |
macros. Perhaps someday all C compilers will do as good a job |
inlining modular code as can now be done by brute-force expansion, |
but now, enough of them seem not to. |
Some compilers issue a lot of warnings about code that is |
dead/unreachable only on some platforms, and also about intentional |
uses of negation on unsigned types. All known cases of each can be |
ignored. |
For a longer but out of date high-level description, see |
http://gee.cs.oswego.edu/dl/html/malloc.html |
* MSPACES |
If MSPACES is defined, then in addition to malloc, free, etc., |
this file also defines mspace_malloc, mspace_free, etc. These |
are versions of malloc routines that take an "mspace" argument |
obtained using create_mspace, to control all internal bookkeeping. |
If ONLY_MSPACES is defined, only these versions are compiled. |
So if you would like to use this allocator for only some allocations, |
and your system malloc for others, you can compile with |
ONLY_MSPACES and then do something like... |
static mspace mymspace = create_mspace(0,0); // for example |
#define mymalloc(bytes) mspace_malloc(mymspace, bytes) |
(Note: If you only need one instance of an mspace, you can instead |
use "USE_DL_PREFIX" to relabel the global malloc.) |
You can similarly create thread-local allocators by storing |
mspaces as thread-locals. For example: |
static __thread mspace tlms = 0; |
void* tlmalloc(size_t bytes) { |
if (tlms == 0) tlms = create_mspace(0, 0); |
return mspace_malloc(tlms, bytes); |
} |
void tlfree(void* mem) { mspace_free(tlms, mem); } |
Unless FOOTERS is defined, each mspace is completely independent. |
You cannot allocate from one and free to another (although |
conformance is only weakly checked, so usage errors are not always |
caught). If FOOTERS is defined, then each chunk carries around a tag |
indicating its originating mspace, and frees are directed to their |
originating spaces. |
------------------------- Compile-time options --------------------------- |
Be careful in setting #define values for numerical constants of type |
size_t. On some systems, literal values are not automatically extended |
to size_t precision unless they are explicitly casted. |
WIN32 default: defined if _WIN32 defined |
Defining WIN32 sets up defaults for MS environment and compilers. |
Otherwise defaults are for unix. |
MALLOC_ALIGNMENT default: (size_t)8 |
Controls the minimum alignment for malloc'ed chunks. It must be a |
power of two and at least 8, even on machines for which smaller |
alignments would suffice. It may be defined as larger than this |
though. Note however that code and data structures are optimized for |
the case of 8-byte alignment. |
MSPACES default: 0 (false) |
If true, compile in support for independent allocation spaces. |
This is only supported if HAVE_MMAP is true. |
ONLY_MSPACES default: 0 (false) |
If true, only compile in mspace versions, not regular versions. |
USE_LOCKS default: 0 (false) |
Causes each call to each public routine to be surrounded with |
pthread or WIN32 mutex lock/unlock. (If set true, this can be |
overridden on a per-mspace basis for mspace versions.) |
FOOTERS default: 0 |
If true, provide extra checking and dispatching by placing |
information in the footers of allocated chunks. This adds |
space and time overhead. |
INSECURE default: 0 |
If true, omit checks for usage errors and heap space overwrites. |
USE_DL_PREFIX default: NOT defined |
Causes compiler to prefix all public routines with the string 'dl'. |
This can be useful when you only want to use this malloc in one part |
of a program, using your regular system malloc elsewhere. |
ABORT default: defined as abort() |
Defines how to abort on failed checks. On most systems, a failed |
check cannot die with an "assert" or even print an informative |
message, because the underlying print routines in turn call malloc, |
which will fail again. Generally, the best policy is to simply call |
abort(). It's not very useful to do more than this because many |
errors due to overwriting will show up as address faults (null, odd |
addresses etc) rather than malloc-triggered checks, so will also |
abort. Also, most compilers know that abort() does not return, so |
can better optimize code conditionally calling it. |
PROCEED_ON_ERROR default: defined as 0 (false) |
Controls whether detected bad addresses cause them to bypassed |
rather than aborting. If set, detected bad arguments to free and |
realloc are ignored. And all bookkeeping information is zeroed out |
upon a detected overwrite of freed heap space, thus losing the |
ability to ever return it from malloc again, but enabling the |
application to proceed. If PROCEED_ON_ERROR is defined, the |
static variable malloc_corruption_error_count is compiled in |
and can be examined to see if errors have occurred. This option |
generates slower code than the default abort policy. |
DEBUG default: NOT defined |
The DEBUG setting is mainly intended for people trying to modify |
this code or diagnose problems when porting to new platforms. |
However, it may also be able to better isolate user errors than just |
using runtime checks. The assertions in the check routines spell |
out in more detail the assumptions and invariants underlying the |
algorithms. The checking is fairly extensive, and will slow down |
execution noticeably. Calling malloc_stats or mallinfo with DEBUG |
set will attempt to check every non-mmapped allocated and free chunk |
in the course of computing the summaries. |
ABORT_ON_ASSERT_FAILURE default: defined as 1 (true) |
Debugging assertion failures can be nearly impossible if your |
version of the assert macro causes malloc to be called, which will |
lead to a cascade of further failures, blowing the runtime stack. |
ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(), |
which will usually make debugging easier. |
MALLOC_FAILURE_ACTION default: sets errno to ENOMEM, or no-op on win32 |
The action to take before "return 0" when malloc fails to be able to |
return memory because there is none available. |
HAVE_MORECORE default: 1 (true) unless win32 or ONLY_MSPACES |
True if this system supports sbrk or an emulation of it. |
MORECORE default: sbrk |
The name of the sbrk-style system routine to call to obtain more |
memory. See below for guidance on writing custom MORECORE |
functions. The type of the argument to sbrk/MORECORE varies across |
systems. It cannot be size_t, because it supports negative |
arguments, so it is normally the signed type of the same width as |
size_t (sometimes declared as "intptr_t"). It doesn't much matter |
though. Internally, we only call it with arguments less than half |
the max value of a size_t, which should work across all reasonable |
possibilities, although sometimes generating compiler warnings. See |
near the end of this file for guidelines for creating a custom |
version of MORECORE. |
MORECORE_CONTIGUOUS default: 1 (true) |
If true, take advantage of fact that consecutive calls to MORECORE |
with positive arguments always return contiguous increasing |
addresses. This is true of unix sbrk. It does not hurt too much to |
set it true anyway, since malloc copes with non-contiguities. |
Setting it false when definitely non-contiguous saves time |
and possibly wasted space it would take to discover this though. |
MORECORE_CANNOT_TRIM default: NOT defined |
True if MORECORE cannot release space back to the system when given |
negative arguments. This is generally necessary only if you are |
using a hand-crafted MORECORE function that cannot handle negative |
arguments. |
HAVE_MMAP default: 1 (true) |
True if this system supports mmap or an emulation of it. If so, and |
HAVE_MORECORE is not true, MMAP is used for all system |
allocation. If set and HAVE_MORECORE is true as well, MMAP is |
primarily used to directly allocate very large blocks. It is also |
used as a backup strategy in cases where MORECORE fails to provide |
space from system. Note: A single call to MUNMAP is assumed to be |
able to unmap memory that may have be allocated using multiple calls |
to MMAP, so long as they are adjacent. |
HAVE_MREMAP default: 1 on linux, else 0 |
If true realloc() uses mremap() to re-allocate large blocks and |
extend or shrink allocation spaces. |
MMAP_CLEARS default: 1 on unix |
True if mmap clears memory so calloc doesn't need to. This is true |
for standard unix mmap using /dev/zero. |
USE_BUILTIN_FFS default: 0 (i.e., not used) |
Causes malloc to use the builtin ffs() function to compute indices. |
Some compilers may recognize and intrinsify ffs to be faster than the |
supplied C version. Also, the case of x86 using gcc is special-cased |
to an asm instruction, so is already as fast as it can be, and so |
this setting has no effect. (On most x86s, the asm version is only |
slightly faster than the C version.) |
malloc_getpagesize default: derive from system includes, or 4096. |
The system page size. To the extent possible, this malloc manages |
memory from the system in page-size units. This may be (and |
usually is) a function rather than a constant. This is ignored |
if WIN32, where page size is determined using getSystemInfo during |
initialization. |
USE_DEV_RANDOM default: 0 (i.e., not used) |
Causes malloc to use /dev/random to initialize secure magic seed for |
stamping footers. Otherwise, the current time is used. |
NO_MALLINFO default: 0 |
If defined, don't compile "mallinfo". This can be a simple way |
of dealing with mismatches between system declarations and |
those in this file. |
MALLINFO_FIELD_TYPE default: size_t |
The type of the fields in the mallinfo struct. This was originally |
defined as "int" in SVID etc, but is more usefully defined as |
size_t. The value is used only if HAVE_USR_INCLUDE_MALLOC_H is not set |
REALLOC_ZERO_BYTES_FREES default: not defined |
This should be set if a call to realloc with zero bytes should |
be the same as a call to free. Some people think it should. Otherwise, |
since this malloc returns a unique pointer for malloc(0), so does |
realloc(p, 0). |
LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H |
LACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H, LACKS_ERRNO_H |
LACKS_STDLIB_H default: NOT defined unless on WIN32 |
Define these if your system does not have these header files. |
You might need to manually insert some of the declarations they provide. |
DEFAULT_GRANULARITY default: page size if MORECORE_CONTIGUOUS, |
system_info.dwAllocationGranularity in WIN32, |
otherwise 64K. |
Also settable using mallopt(M_GRANULARITY, x) |
The unit for allocating and deallocating memory from the system. On |
most systems with contiguous MORECORE, there is no reason to |
make this more than a page. However, systems with MMAP tend to |
either require or encourage larger granularities. You can increase |
this value to prevent system allocation functions to be called so |
often, especially if they are slow. The value must be at least one |
page and must be a power of two. Setting to 0 causes initialization |
to either page size or win32 region size. (Note: In previous |
versions of malloc, the equivalent of this option was called |
"TOP_PAD") |
DEFAULT_TRIM_THRESHOLD default: 2MB |
Also settable using mallopt(M_TRIM_THRESHOLD, x) |
The maximum amount of unused top-most memory to keep before |
releasing via malloc_trim in free(). Automatic trimming is mainly |
useful in long-lived programs using contiguous MORECORE. Because |
trimming via sbrk can be slow on some systems, and can sometimes be |
wasteful (in cases where programs immediately afterward allocate |
more large chunks) the value should be high enough so that your |
overall system performance would improve by releasing this much |
memory. As a rough guide, you might set to a value close to the |
average size of a process (program) running on your system. |
Releasing this much memory would allow such a process to run in |
memory. Generally, it is worth tuning trim thresholds when a |
program undergoes phases where several large chunks are allocated |
and released in ways that can reuse each other's storage, perhaps |
mixed with phases where there are no such chunks at all. The trim |
value must be greater than page size to have any useful effect. To |
disable trimming completely, you can set to MAX_SIZE_T. Note that the trick |
some people use of mallocing a huge space and then freeing it at |
program startup, in an attempt to reserve system memory, doesn't |
have the intended effect under automatic trimming, since that memory |
will immediately be returned to the system. |
DEFAULT_MMAP_THRESHOLD default: 256K |
Also settable using mallopt(M_MMAP_THRESHOLD, x) |
The request size threshold for using MMAP to directly service a |
request. Requests of at least this size that cannot be allocated |
using already-existing space will be serviced via mmap. (If enough |
normal freed space already exists it is used instead.) Using mmap |
segregates relatively large chunks of memory so that they can be |
individually obtained and released from the host system. A request |
serviced through mmap is never reused by any other request (at least |
not directly; the system may just so happen to remap successive |
requests to the same locations). Segregating space in this way has |
the benefits that: Mmapped space can always be individually released |
back to the system, which helps keep the system level memory demands |
of a long-lived program low. Also, mapped memory doesn't become |
`locked' between other chunks, as can happen with normally allocated |
chunks, which means that even trimming via malloc_trim would not |
release them. However, it has the disadvantage that the space |
cannot be reclaimed, consolidated, and then used to service later |
requests, as happens with normal chunks. The advantages of mmap |
nearly always outweigh disadvantages for "large" chunks, but the |
value of "large" may vary across systems. The default is an |
empirically derived value that works well in most systems. You can |
disable mmap by setting to MAX_SIZE_T. |
*/ |
/** @addtogroup libcmalloc malloc |
* @brief Malloc originally written by Doug Lea and ported to HelenOS. |
* @ingroup libc |
* @{ |
*/ |
/** @file |
*/ |
#include <sys/types.h> /* For size_t */ |
/** Non-default helenos customizations */ |
#define LACKS_FCNTL_H |
#define LACKS_SYS_MMAN_H |
#define LACKS_SYS_PARAM_H |
#undef HAVE_MMAP |
#define HAVE_MMAP 0 |
#define LACKS_ERRNO_H |
/* Set errno? */ |
#undef MALLOC_FAILURE_ACTION |
#define MALLOC_FAILURE_ACTION |
/* The maximum possible size_t value has all bits set */ |
#define MAX_SIZE_T (~(size_t)0) |
#define ONLY_MSPACES 0 |
#define MSPACES 0 |
#ifdef MALLOC_ALIGNMENT_16 |
#define MALLOC_ALIGNMENT ((size_t)16U) |
#else |
#define MALLOC_ALIGNMENT ((size_t)8U) |
#endif |
#define FOOTERS 0 |
#define ABORT \ |
{ \ |
DEBUG("%s abort in %s on line %d\n", __FILE__, __func__, __LINE__); \ |
abort(); \ |
} |
#define ABORT_ON_ASSERT_FAILURE 1 |
#define PROCEED_ON_ERROR 0 |
#define USE_LOCKS 1 |
#define INSECURE 0 |
#define HAVE_MMAP 0 |
#define MMAP_CLEARS 1 |
#define HAVE_MORECORE 1 |
#define MORECORE_CONTIGUOUS 1 |
#define MORECORE sbrk |
#define DEFAULT_GRANULARITY (0) /* 0 means to compute in init_mparams */ |
#ifndef DEFAULT_TRIM_THRESHOLD |
#ifndef MORECORE_CANNOT_TRIM |
#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U) |
#else /* MORECORE_CANNOT_TRIM */ |
#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T |
#endif /* MORECORE_CANNOT_TRIM */ |
#endif /* DEFAULT_TRIM_THRESHOLD */ |
#ifndef DEFAULT_MMAP_THRESHOLD |
#if HAVE_MMAP |
#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U) |
#else /* HAVE_MMAP */ |
#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T |
#endif /* HAVE_MMAP */ |
#endif /* DEFAULT_MMAP_THRESHOLD */ |
#ifndef USE_BUILTIN_FFS |
#define USE_BUILTIN_FFS 0 |
#endif /* USE_BUILTIN_FFS */ |
#ifndef USE_DEV_RANDOM |
#define USE_DEV_RANDOM 0 |
#endif /* USE_DEV_RANDOM */ |
#ifndef NO_MALLINFO |
#define NO_MALLINFO 0 |
#endif /* NO_MALLINFO */ |
#ifndef MALLINFO_FIELD_TYPE |
#define MALLINFO_FIELD_TYPE size_t |
#endif /* MALLINFO_FIELD_TYPE */ |
/* |
mallopt tuning options. SVID/XPG defines four standard parameter |
numbers for mallopt, normally defined in malloc.h. None of these |
are used in this malloc, so setting them has no effect. But this |
malloc does support the following options. |
*/ |
#define M_TRIM_THRESHOLD (-1) |
#define M_GRANULARITY (-2) |
#define M_MMAP_THRESHOLD (-3) |
/* |
======================================================================== |
To make a fully customizable malloc.h header file, cut everything |
above this line, put into file malloc.h, edit to suit, and #include it |
on the next line, as well as in programs that use this malloc. |
======================================================================== |
*/ |
#include "malloc.h" |
/*------------------------------ internal #includes ---------------------- */ |
#include <stdio.h> /* for printing in malloc_stats */ |
#include <string.h> |
#ifndef LACKS_ERRNO_H |
#include <errno.h> /* for MALLOC_FAILURE_ACTION */ |
#endif /* LACKS_ERRNO_H */ |
#if FOOTERS |
#include <time.h> /* for magic initialization */ |
#endif /* FOOTERS */ |
#ifndef LACKS_STDLIB_H |
#include <stdlib.h> /* for abort() */ |
#endif /* LACKS_STDLIB_H */ |
#ifdef DEBUG |
#if ABORT_ON_ASSERT_FAILURE |
#define assert(x) {if(!(x)) {DEBUG(#x);ABORT;}} |
#else /* ABORT_ON_ASSERT_FAILURE */ |
#include <assert.h> |
#endif /* ABORT_ON_ASSERT_FAILURE */ |
#else /* DEBUG */ |
#define assert(x) |
#endif /* DEBUG */ |
#if USE_BUILTIN_FFS |
#ifndef LACKS_STRINGS_H |
#include <strings.h> /* for ffs */ |
#endif /* LACKS_STRINGS_H */ |
#endif /* USE_BUILTIN_FFS */ |
#if HAVE_MMAP |
#ifndef LACKS_SYS_MMAN_H |
#include <sys/mman.h> /* for mmap */ |
#endif /* LACKS_SYS_MMAN_H */ |
#ifndef LACKS_FCNTL_H |
#include <fcntl.h> |
#endif /* LACKS_FCNTL_H */ |
#endif /* HAVE_MMAP */ |
#if HAVE_MORECORE |
#ifndef LACKS_UNISTD_H |
#include <unistd.h> /* for sbrk */ |
#else /* LACKS_UNISTD_H */ |
#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) |
extern void* sbrk(ptrdiff_t); |
#endif /* FreeBSD etc */ |
#endif /* LACKS_UNISTD_H */ |
#endif /* HAVE_MMAP */ |
#ifndef WIN32 |
#ifndef malloc_getpagesize |
# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ |
# ifndef _SC_PAGE_SIZE |
# define _SC_PAGE_SIZE _SC_PAGESIZE |
# endif |
# endif |
# ifdef _SC_PAGE_SIZE |
# define malloc_getpagesize sysconf(_SC_PAGE_SIZE) |
# else |
# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) |
extern size_t getpagesize(); |
# define malloc_getpagesize getpagesize() |
# else |
# ifdef WIN32 /* use supplied emulation of getpagesize */ |
# define malloc_getpagesize getpagesize() |
# else |
# ifndef LACKS_SYS_PARAM_H |
# include <sys/param.h> |
# endif |
# ifdef EXEC_PAGESIZE |
# define malloc_getpagesize EXEC_PAGESIZE |
# else |
# ifdef NBPG |
# ifndef CLSIZE |
# define malloc_getpagesize NBPG |
# else |
# define malloc_getpagesize (NBPG * CLSIZE) |
# endif |
# else |
# ifdef NBPC |
# define malloc_getpagesize NBPC |
# else |
# ifdef PAGESIZE |
# define malloc_getpagesize PAGESIZE |
# else /* just guess */ |
# define malloc_getpagesize ((size_t)4096U) |
# endif |
# endif |
# endif |
# endif |
# endif |
# endif |
# endif |
#endif |
#endif |
/* ------------------- size_t and alignment properties -------------------- */ |
/* The byte and bit size of a size_t */ |
#define SIZE_T_SIZE (sizeof(size_t)) |
#define SIZE_T_BITSIZE (sizeof(size_t) << 3) |
/* Some constants coerced to size_t */ |
/* Annoying but necessary to avoid errors on some plaftorms */ |
#define SIZE_T_ZERO ((size_t)0) |
#define SIZE_T_ONE ((size_t)1) |
#define SIZE_T_TWO ((size_t)2) |
#define TWO_SIZE_T_SIZES (SIZE_T_SIZE<<1) |
#define FOUR_SIZE_T_SIZES (SIZE_T_SIZE<<2) |
#define SIX_SIZE_T_SIZES (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES) |
#define HALF_MAX_SIZE_T (MAX_SIZE_T / 2U) |
/* The bit mask value corresponding to MALLOC_ALIGNMENT */ |
#define CHUNK_ALIGN_MASK (MALLOC_ALIGNMENT - SIZE_T_ONE) |
/* True if address a has acceptable alignment */ |
#define is_aligned(A) (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0) |
/* the number of bytes to offset an address to align it */ |
#define align_offset(A)\ |
((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\ |
((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK)) |
/* -------------------------- MMAP preliminaries ------------------------- */ |
/* |
If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and |
checks to fail so compiler optimizer can delete code rather than |
using so many "#if"s. |
*/ |
/* MORECORE and MMAP must return MFAIL on failure */ |
#define MFAIL ((void*)(MAX_SIZE_T)) |
#define CMFAIL ((char*)(MFAIL)) /* defined for convenience */ |
#if !HAVE_MMAP |
#define IS_MMAPPED_BIT (SIZE_T_ZERO) |
#define USE_MMAP_BIT (SIZE_T_ZERO) |
#define CALL_MMAP(s) MFAIL |
#define CALL_MUNMAP(a, s) (-1) |
#define DIRECT_MMAP(s) MFAIL |
#else /* HAVE_MMAP */ |
#define IS_MMAPPED_BIT (SIZE_T_ONE) |
#define USE_MMAP_BIT (SIZE_T_ONE) |
#ifndef WIN32 |
#define CALL_MUNMAP(a, s) munmap((a), (s)) |
#define MMAP_PROT (PROT_READ|PROT_WRITE) |
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) |
#define MAP_ANONYMOUS MAP_ANON |
#endif /* MAP_ANON */ |
#ifdef MAP_ANONYMOUS |
#define MMAP_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS) |
#define CALL_MMAP(s) mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0) |
#else /* MAP_ANONYMOUS */ |
/* |
Nearly all versions of mmap support MAP_ANONYMOUS, so the following |
is unlikely to be needed, but is supplied just in case. |
*/ |
#define MMAP_FLAGS (MAP_PRIVATE) |
static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */ |
#define CALL_MMAP(s) ((dev_zero_fd < 0) ? \ |
(dev_zero_fd = open("/dev/zero", O_RDWR), \ |
mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \ |
mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) |
#endif /* MAP_ANONYMOUS */ |
#define DIRECT_MMAP(s) CALL_MMAP(s) |
#else /* WIN32 */ |
/* Win32 MMAP via VirtualAlloc */ |
static void* win32mmap(size_t size) { |
void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); |
return (ptr != 0)? ptr: MFAIL; |
} |
/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */ |
static void* win32direct_mmap(size_t size) { |
void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, |
PAGE_READWRITE); |
return (ptr != 0)? ptr: MFAIL; |
} |
/* This function supports releasing coalesed segments */ |
static int win32munmap(void* ptr, size_t size) { |
MEMORY_BASIC_INFORMATION minfo; |
char* cptr = ptr; |
while (size) { |
if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0) |
return -1; |
if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr || |
minfo.State != MEM_COMMIT || minfo.RegionSize > size) |
return -1; |
if (VirtualFree(cptr, 0, MEM_RELEASE) == 0) |
return -1; |
cptr += minfo.RegionSize; |
size -= minfo.RegionSize; |
} |
return 0; |
} |
#define CALL_MMAP(s) win32mmap(s) |
#define CALL_MUNMAP(a, s) win32munmap((a), (s)) |
#define DIRECT_MMAP(s) win32direct_mmap(s) |
#endif /* WIN32 */ |
#endif /* HAVE_MMAP */ |
#if HAVE_MMAP && HAVE_MREMAP |
#define CALL_MREMAP(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv)) |
#else /* HAVE_MMAP && HAVE_MREMAP */ |
#define CALL_MREMAP(addr, osz, nsz, mv) MFAIL |
#endif /* HAVE_MMAP && HAVE_MREMAP */ |
#if HAVE_MORECORE |
#define CALL_MORECORE(S) MORECORE(S) |
#else /* HAVE_MORECORE */ |
#define CALL_MORECORE(S) MFAIL |
#endif /* HAVE_MORECORE */ |
/* mstate bit set if continguous morecore disabled or failed */ |
#define USE_NONCONTIGUOUS_BIT (4U) |
/* segment bit set in create_mspace_with_base */ |
#define EXTERN_BIT (8U) |
/* --------------------------- Lock preliminaries ------------------------ */ |
#if USE_LOCKS |
/* |
When locks are defined, there are up to two global locks: |
* If HAVE_MORECORE, morecore_mutex protects sequences of calls to |
MORECORE. In many cases sys_alloc requires two calls, that should |
not be interleaved with calls by other threads. This does not |
protect against direct calls to MORECORE by other threads not |
using this lock, so there is still code to cope the best we can on |
interference. |
* magic_init_mutex ensures that mparams.magic and other |
unique mparams values are initialized only once. |
*/ |
/* By default use posix locks */ |
#include <futex.h> |
#define MLOCK_T atomic_t |
#define INITIAL_LOCK(l) futex_initialize(l, 1) |
/* futex_down cannot fail, but can return different |
* retvals for OK |
*/ |
#define ACQUIRE_LOCK(l) ({futex_down(l);0;}) |
#define RELEASE_LOCK(l) futex_up(l) |
#if HAVE_MORECORE |
static MLOCK_T morecore_mutex = FUTEX_INITIALIZER; |
#endif /* HAVE_MORECORE */ |
static MLOCK_T magic_init_mutex = FUTEX_INITIALIZER; |
#define USE_LOCK_BIT (2U) |
#else /* USE_LOCKS */ |
#define USE_LOCK_BIT (0U) |
#define INITIAL_LOCK(l) |
#endif /* USE_LOCKS */ |
#if USE_LOCKS && HAVE_MORECORE |
#define ACQUIRE_MORECORE_LOCK() ACQUIRE_LOCK(&morecore_mutex); |
#define RELEASE_MORECORE_LOCK() RELEASE_LOCK(&morecore_mutex); |
#else /* USE_LOCKS && HAVE_MORECORE */ |
#define ACQUIRE_MORECORE_LOCK() |
#define RELEASE_MORECORE_LOCK() |
#endif /* USE_LOCKS && HAVE_MORECORE */ |
#if USE_LOCKS |
#define ACQUIRE_MAGIC_INIT_LOCK() ACQUIRE_LOCK(&magic_init_mutex); |
#define RELEASE_MAGIC_INIT_LOCK() RELEASE_LOCK(&magic_init_mutex); |
#else /* USE_LOCKS */ |
#define ACQUIRE_MAGIC_INIT_LOCK() |
#define RELEASE_MAGIC_INIT_LOCK() |
#endif /* USE_LOCKS */ |
/* ----------------------- Chunk representations ------------------------ */ |
/* |
(The following includes lightly edited explanations by Colin Plumb.) |
The malloc_chunk declaration below is misleading (but accurate and |
necessary). It declares a "view" into memory allowing access to |
necessary fields at known offsets from a given base. |
Chunks of memory are maintained using a `boundary tag' method as |
originally described by Knuth. (See the paper by Paul Wilson |
ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such |
techniques.) Sizes of free chunks are stored both in the front of |
each chunk and at the end. This makes consolidating fragmented |
chunks into bigger chunks fast. The head fields also hold bits |
representing whether chunks are free or in use. |
Here are some pictures to make it clearer. They are "exploded" to |
show that the state of a chunk can be thought of as extending from |
the high 31 bits of the head field of its header through the |
prev_foot and PINUSE_BIT bit of the following chunk header. |
A chunk that's in use looks like: |
chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Size of previous chunk (if P = 1) | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| |
| Size of this chunk 1| +-+ |
mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| | |
+- -+ |
| | |
+- -+ |
| : |
+- size - sizeof(size_t) available payload bytes -+ |
: | |
chunk-> +- -+ |
| | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1| |
| Size of next chunk (may or may not be in use) | +-+ |
mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
And if it's free, it looks like this: |
chunk-> +- -+ |
| User payload (must be in use, or we would have merged!) | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| |
| Size of this chunk 0| +-+ |
mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Next pointer | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Prev pointer | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| : |
+- size - sizeof(struct chunk) unused bytes -+ |
: | |
chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Size of this chunk | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0| |
| Size of next chunk (must be in use, or we would have merged)| +-+ |
mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| : |
+- User payload -+ |
: | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|0| |
+-+ |
Note that since we always merge adjacent free chunks, the chunks |
adjacent to a free chunk must be in use. |
Given a pointer to a chunk (which can be derived trivially from the |
payload pointer) we can, in O(1) time, find out whether the adjacent |
chunks are free, and if so, unlink them from the lists that they |
are on and merge them with the current chunk. |
Chunks always begin on even word boundaries, so the mem portion |
(which is returned to the user) is also on an even word boundary, and |
thus at least double-word aligned. |
The P (PINUSE_BIT) bit, stored in the unused low-order bit of the |
chunk size (which is always a multiple of two words), is an in-use |
bit for the *previous* chunk. If that bit is *clear*, then the |
word before the current chunk size contains the previous chunk |
size, and can be used to find the front of the previous chunk. |
The very first chunk allocated always has this bit set, preventing |
access to non-existent (or non-owned) memory. If pinuse is set for |
any given chunk, then you CANNOT determine the size of the |
previous chunk, and might even get a memory addressing fault when |
trying to do so. |
The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of |
the chunk size redundantly records whether the current chunk is |
inuse. This redundancy enables usage checks within free and realloc, |
and reduces indirection when freeing and consolidating chunks. |
Each freshly allocated chunk must have both cinuse and pinuse set. |
That is, each allocated chunk borders either a previously allocated |
and still in-use chunk, or the base of its memory arena. This is |
ensured by making all allocations from the the `lowest' part of any |
found chunk. Further, no free chunk physically borders another one, |
so each free chunk is known to be preceded and followed by either |
inuse chunks or the ends of memory. |
Note that the `foot' of the current chunk is actually represented |
as the prev_foot of the NEXT chunk. This makes it easier to |
deal with alignments etc but can be very confusing when trying |
to extend or adapt this code. |
The exceptions to all this are |
1. The special chunk `top' is the top-most available chunk (i.e., |
the one bordering the end of available memory). It is treated |
specially. Top is never included in any bin, is used only if |
no other chunk is available, and is released back to the |
system if it is very large (see M_TRIM_THRESHOLD). In effect, |
the top chunk is treated as larger (and thus less well |
fitting) than any other available chunk. The top chunk |
doesn't update its trailing size field since there is no next |
contiguous chunk that would have to index off it. However, |
space is still allocated for it (TOP_FOOT_SIZE) to enable |
separation or merging when space is extended. |
3. Chunks allocated via mmap, which have the lowest-order bit |
(IS_MMAPPED_BIT) set in their prev_foot fields, and do not set |
PINUSE_BIT in their head fields. Because they are allocated |
one-by-one, each must carry its own prev_foot field, which is |
also used to hold the offset this chunk has within its mmapped |
region, which is needed to preserve alignment. Each mmapped |
chunk is trailed by the first two fields of a fake next-chunk |
for sake of usage checks. |
*/ |
struct malloc_chunk { |
size_t prev_foot; /* Size of previous chunk (if free). */ |
size_t head; /* Size and inuse bits. */ |
struct malloc_chunk* fd; /* double links -- used only if free. */ |
struct malloc_chunk* bk; |
}; |
typedef struct malloc_chunk mchunk; |
typedef struct malloc_chunk* mchunkptr; |
typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */ |
typedef unsigned int bindex_t; /* Described below */ |
typedef unsigned int binmap_t; /* Described below */ |
typedef unsigned int flag_t; /* The type of various bit flag sets */ |
/* ------------------- Chunks sizes and alignments ----------------------- */ |
#define MCHUNK_SIZE (sizeof(mchunk)) |
#if FOOTERS |
#define CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) |
#else /* FOOTERS */ |
#define CHUNK_OVERHEAD (SIZE_T_SIZE) |
#endif /* FOOTERS */ |
/* MMapped chunks need a second word of overhead ... */ |
#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) |
/* ... and additional padding for fake next-chunk at foot */ |
#define MMAP_FOOT_PAD (FOUR_SIZE_T_SIZES) |
/* The smallest size we can malloc is an aligned minimal chunk */ |
#define MIN_CHUNK_SIZE\ |
((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) |
/* conversion from malloc headers to user pointers, and back */ |
#define chunk2mem(p) ((void*)((char*)(p) + TWO_SIZE_T_SIZES)) |
#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES)) |
/* chunk associated with aligned address A */ |
#define align_as_chunk(A) (mchunkptr)((A) + align_offset(chunk2mem(A))) |
/* Bounds on request (not chunk) sizes. */ |
#define MAX_REQUEST ((-MIN_CHUNK_SIZE) << 2) |
#define MIN_REQUEST (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE) |
/* pad request bytes into a usable size */ |
#define pad_request(req) \ |
(((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) |
/* pad request, checking for minimum (but not maximum) */ |
#define request2size(req) \ |
(((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req)) |
/* ------------------ Operations on head and foot fields ----------------- */ |
/* |
The head field of a chunk is or'ed with PINUSE_BIT when previous |
adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in |
use. If the chunk was obtained with mmap, the prev_foot field has |
IS_MMAPPED_BIT set, otherwise holding the offset of the base of the |
mmapped region to the base of the chunk. |
*/ |
#define PINUSE_BIT (SIZE_T_ONE) |
#define CINUSE_BIT (SIZE_T_TWO) |
#define INUSE_BITS (PINUSE_BIT|CINUSE_BIT) |
/* Head value for fenceposts */ |
#define FENCEPOST_HEAD (INUSE_BITS|SIZE_T_SIZE) |
/* extraction of fields from head words */ |
#define cinuse(p) ((p)->head & CINUSE_BIT) |
#define pinuse(p) ((p)->head & PINUSE_BIT) |
#define chunksize(p) ((p)->head & ~(INUSE_BITS)) |
#define clear_pinuse(p) ((p)->head &= ~PINUSE_BIT) |
#define clear_cinuse(p) ((p)->head &= ~CINUSE_BIT) |
/* Treat space at ptr +/- offset as a chunk */ |
#define chunk_plus_offset(p, s) ((mchunkptr)(((char*)(p)) + (s))) |
#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s))) |
/* Ptr to next or previous physical malloc_chunk. */ |
#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~INUSE_BITS))) |
#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) )) |
/* extract next chunk's pinuse bit */ |
#define next_pinuse(p) ((next_chunk(p)->head) & PINUSE_BIT) |
/* Get/set size at footer */ |
#define get_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot) |
#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s)) |
/* Set size, pinuse bit, and foot */ |
#define set_size_and_pinuse_of_free_chunk(p, s)\ |
((p)->head = (s|PINUSE_BIT), set_foot(p, s)) |
/* Set size, pinuse bit, foot, and clear next pinuse */ |
#define set_free_with_pinuse(p, s, n)\ |
(clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s)) |
#define is_mmapped(p)\ |
(!((p)->head & PINUSE_BIT) && ((p)->prev_foot & IS_MMAPPED_BIT)) |
/* Get the internal overhead associated with chunk p */ |
#define overhead_for(p)\ |
(is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD) |
/* Return true if malloced space is not necessarily cleared */ |
#if MMAP_CLEARS |
#define calloc_must_clear(p) (!is_mmapped(p)) |
#else /* MMAP_CLEARS */ |
#define calloc_must_clear(p) (1) |
#endif /* MMAP_CLEARS */ |
/* ---------------------- Overlaid data structures ----------------------- */ |
/* |
When chunks are not in use, they are treated as nodes of either |
lists or trees. |
"Small" chunks are stored in circular doubly-linked lists, and look |
like this: |
chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Size of previous chunk | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
`head:' | Size of chunk, in bytes |P| |
mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Forward pointer to next chunk in list | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Back pointer to previous chunk in list | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Unused space (may be 0 bytes long) . |
. . |
. | |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
`foot:' | Size of chunk, in bytes | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
Larger chunks are kept in a form of bitwise digital trees (aka |
tries) keyed on chunksizes. Because malloc_tree_chunks are only for |
free chunks greater than 256 bytes, their size doesn't impose any |
constraints on user chunk sizes. Each node looks like: |
chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Size of previous chunk | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
`head:' | Size of chunk, in bytes |P| |
mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Forward pointer to next chunk of same size | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Back pointer to previous chunk of same size | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Pointer to left child (child[0]) | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Pointer to right child (child[1]) | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Pointer to parent | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| bin index of this chunk | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Unused space . |
. | |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
`foot:' | Size of chunk, in bytes | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
Each tree holding treenodes is a tree of unique chunk sizes. Chunks |
of the same size are arranged in a circularly-linked list, with only |
the oldest chunk (the next to be used, in our FIFO ordering) |
actually in the tree. (Tree members are distinguished by a non-null |
parent pointer.) If a chunk with the same size an an existing node |
is inserted, it is linked off the existing node using pointers that |
work in the same way as fd/bk pointers of small chunks. |
Each tree contains a power of 2 sized range of chunk sizes (the |
smallest is 0x100 <= x < 0x180), which is is divided in half at each |
tree level, with the chunks in the smaller half of the range (0x100 |
<= x < 0x140 for the top nose) in the left subtree and the larger |
half (0x140 <= x < 0x180) in the right subtree. This is, of course, |
done by inspecting individual bits. |
Using these rules, each node's left subtree contains all smaller |
sizes than its right subtree. However, the node at the root of each |
subtree has no particular ordering relationship to either. (The |
dividing line between the subtree sizes is based on trie relation.) |
If we remove the last chunk of a given size from the interior of the |
tree, we need to replace it with a leaf node. The tree ordering |
rules permit a node to be replaced by any leaf below it. |
The smallest chunk in a tree (a common operation in a best-fit |
allocator) can be found by walking a path to the leftmost leaf in |
the tree. Unlike a usual binary tree, where we follow left child |
pointers until we reach a null, here we follow the right child |
pointer any time the left one is null, until we reach a leaf with |
both child pointers null. The smallest chunk in the tree will be |
somewhere along that path. |
The worst case number of steps to add, find, or remove a node is |
bounded by the number of bits differentiating chunks within |
bins. Under current bin calculations, this ranges from 6 up to 21 |
(for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case |
is of course much better. |
*/ |
struct malloc_tree_chunk { |
/* The first four fields must be compatible with malloc_chunk */ |
size_t prev_foot; |
size_t head; |
struct malloc_tree_chunk* fd; |
struct malloc_tree_chunk* bk; |
struct malloc_tree_chunk* child[2]; |
struct malloc_tree_chunk* parent; |
bindex_t index; |
}; |
typedef struct malloc_tree_chunk tchunk; |
typedef struct malloc_tree_chunk* tchunkptr; |
typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */ |
/* A little helper macro for trees */ |
#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1]) |
/* ----------------------------- Segments -------------------------------- */ |
/* |
Each malloc space may include non-contiguous segments, held in a |
list headed by an embedded malloc_segment record representing the |
top-most space. Segments also include flags holding properties of |
the space. Large chunks that are directly allocated by mmap are not |
included in this list. They are instead independently created and |
destroyed without otherwise keeping track of them. |
Segment management mainly comes into play for spaces allocated by |
MMAP. Any call to MMAP might or might not return memory that is |
adjacent to an existing segment. MORECORE normally contiguously |
extends the current space, so this space is almost always adjacent, |
which is simpler and faster to deal with. (This is why MORECORE is |
used preferentially to MMAP when both are available -- see |
sys_alloc.) When allocating using MMAP, we don't use any of the |
hinting mechanisms (inconsistently) supported in various |
implementations of unix mmap, or distinguish reserving from |
committing memory. Instead, we just ask for space, and exploit |
contiguity when we get it. It is probably possible to do |
better than this on some systems, but no general scheme seems |
to be significantly better. |
Management entails a simpler variant of the consolidation scheme |
used for chunks to reduce fragmentation -- new adjacent memory is |
normally prepended or appended to an existing segment. However, |
there are limitations compared to chunk consolidation that mostly |
reflect the fact that segment processing is relatively infrequent |
(occurring only when getting memory from system) and that we |
don't expect to have huge numbers of segments: |
* Segments are not indexed, so traversal requires linear scans. (It |
would be possible to index these, but is not worth the extra |
overhead and complexity for most programs on most platforms.) |
* New segments are only appended to old ones when holding top-most |
memory; if they cannot be prepended to others, they are held in |
different segments. |
Except for the top-most segment of an mstate, each segment record |
is kept at the tail of its segment. Segments are added by pushing |
segment records onto the list headed by &mstate.seg for the |
containing mstate. |
Segment flags control allocation/merge/deallocation policies: |
* If EXTERN_BIT set, then we did not allocate this segment, |
and so should not try to deallocate or merge with others. |
(This currently holds only for the initial segment passed |
into create_mspace_with_base.) |
* If IS_MMAPPED_BIT set, the segment may be merged with |
other surrounding mmapped segments and trimmed/de-allocated |
using munmap. |
* If neither bit is set, then the segment was obtained using |
MORECORE so can be merged with surrounding MORECORE'd segments |
and deallocated/trimmed using MORECORE with negative arguments. |
*/ |
struct malloc_segment { |
char* base; /* base address */ |
size_t size; /* allocated size */ |
struct malloc_segment* next; /* ptr to next segment */ |
flag_t sflags; /* mmap and extern flag */ |
}; |
#define is_mmapped_segment(S) ((S)->sflags & IS_MMAPPED_BIT) |
#define is_extern_segment(S) ((S)->sflags & EXTERN_BIT) |
typedef struct malloc_segment msegment; |
typedef struct malloc_segment* msegmentptr; |
/* ---------------------------- malloc_state ----------------------------- */ |
/* |
A malloc_state holds all of the bookkeeping for a space. |
The main fields are: |
Top |
The topmost chunk of the currently active segment. Its size is |
cached in topsize. The actual size of topmost space is |
topsize+TOP_FOOT_SIZE, which includes space reserved for adding |
fenceposts and segment records if necessary when getting more |
space from the system. The size at which to autotrim top is |
cached from mparams in trim_check, except that it is disabled if |
an autotrim fails. |
Designated victim (dv) |
This is the preferred chunk for servicing small requests that |
don't have exact fits. It is normally the chunk split off most |
recently to service another small request. Its size is cached in |
dvsize. The link fields of this chunk are not maintained since it |
is not kept in a bin. |
SmallBins |
An array of bin headers for free chunks. These bins hold chunks |
with sizes less than MIN_LARGE_SIZE bytes. Each bin contains |
chunks of all the same size, spaced 8 bytes apart. To simplify |
use in double-linked lists, each bin header acts as a malloc_chunk |
pointing to the real first node, if it exists (else pointing to |
itself). This avoids special-casing for headers. But to avoid |
waste, we allocate only the fd/bk pointers of bins, and then use |
repositioning tricks to treat these as the fields of a chunk. |
TreeBins |
Treebins are pointers to the roots of trees holding a range of |
sizes. There are 2 equally spaced treebins for each power of two |
from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything |
larger. |
Bin maps |
There is one bit map for small bins ("smallmap") and one for |
treebins ("treemap). Each bin sets its bit when non-empty, and |
clears the bit when empty. Bit operations are then used to avoid |
bin-by-bin searching -- nearly all "search" is done without ever |
looking at bins that won't be selected. The bit maps |
conservatively use 32 bits per map word, even if on 64bit system. |
For a good description of some of the bit-based techniques used |
here, see Henry S. Warren Jr's book "Hacker's Delight" (and |
supplement at http://hackersdelight.org/). Many of these are |
intended to reduce the branchiness of paths through malloc etc, as |
well as to reduce the number of memory locations read or written. |
Segments |
A list of segments headed by an embedded malloc_segment record |
representing the initial space. |
Address check support |
The least_addr field is the least address ever obtained from |
MORECORE or MMAP. Attempted frees and reallocs of any address less |
than this are trapped (unless INSECURE is defined). |
Magic tag |
A cross-check field that should always hold same value as mparams.magic. |
Flags |
Bits recording whether to use MMAP, locks, or contiguous MORECORE |
Statistics |
Each space keeps track of current and maximum system memory |
obtained via MORECORE or MMAP. |
Locking |
If USE_LOCKS is defined, the "mutex" lock is acquired and released |
around every public call using this mspace. |
*/ |
/* Bin types, widths and sizes */ |
#define NSMALLBINS (32U) |
#define NTREEBINS (32U) |
#define SMALLBIN_SHIFT (3U) |
#define SMALLBIN_WIDTH (SIZE_T_ONE << SMALLBIN_SHIFT) |
#define TREEBIN_SHIFT (8U) |
#define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT) |
#define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE) |
#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD) |
struct malloc_state { |
binmap_t smallmap; |
binmap_t treemap; |
size_t dvsize; |
size_t topsize; |
char* least_addr; |
mchunkptr dv; |
mchunkptr top; |
size_t trim_check; |
size_t magic; |
mchunkptr smallbins[(NSMALLBINS+1)*2]; |
tbinptr treebins[NTREEBINS]; |
size_t footprint; |
size_t max_footprint; |
flag_t mflags; |
#if USE_LOCKS |
MLOCK_T mutex; /* locate lock among fields that rarely change */ |
#endif /* USE_LOCKS */ |
msegment seg; |
}; |
typedef struct malloc_state* mstate; |
/* ------------- Global malloc_state and malloc_params ------------------- */ |
/* |
malloc_params holds global properties, including those that can be |
dynamically set using mallopt. There is a single instance, mparams, |
initialized in init_mparams. |
*/ |
struct malloc_params { |
size_t magic; |
size_t page_size; |
size_t granularity; |
size_t mmap_threshold; |
size_t trim_threshold; |
flag_t default_mflags; |
}; |
static struct malloc_params mparams; |
/* The global malloc_state used for all non-"mspace" calls */ |
static struct malloc_state _gm_; |
#define gm (&_gm_) |
#define is_global(M) ((M) == &_gm_) |
#define is_initialized(M) ((M)->top != 0) |
/* -------------------------- system alloc setup ------------------------- */ |
/* Operations on mflags */ |
#define use_lock(M) ((M)->mflags & USE_LOCK_BIT) |
#define enable_lock(M) ((M)->mflags |= USE_LOCK_BIT) |
#define disable_lock(M) ((M)->mflags &= ~USE_LOCK_BIT) |
#define use_mmap(M) ((M)->mflags & USE_MMAP_BIT) |
#define enable_mmap(M) ((M)->mflags |= USE_MMAP_BIT) |
#define disable_mmap(M) ((M)->mflags &= ~USE_MMAP_BIT) |
#define use_noncontiguous(M) ((M)->mflags & USE_NONCONTIGUOUS_BIT) |
#define disable_contiguous(M) ((M)->mflags |= USE_NONCONTIGUOUS_BIT) |
#define set_lock(M,L)\ |
((M)->mflags = (L)?\ |
((M)->mflags | USE_LOCK_BIT) :\ |
((M)->mflags & ~USE_LOCK_BIT)) |
/* page-align a size */ |
#define page_align(S)\ |
(((S) + (mparams.page_size)) & ~(mparams.page_size - SIZE_T_ONE)) |
/* granularity-align a size */ |
#define granularity_align(S)\ |
(((S) + (mparams.granularity)) & ~(mparams.granularity - SIZE_T_ONE)) |
#define is_page_aligned(S)\ |
(((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0) |
#define is_granularity_aligned(S)\ |
(((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0) |
/* True if segment S holds address A */ |
#define segment_holds(S, A)\ |
((char*)(A) >= S->base && (char*)(A) < S->base + S->size) |
/* Return segment holding given address */ |
static msegmentptr segment_holding(mstate m, char* addr) { |
msegmentptr sp = &m->seg; |
for (;;) { |
if (addr >= sp->base && addr < sp->base + sp->size) |
return sp; |
if ((sp = sp->next) == 0) |
return 0; |
} |
} |
/* Return true if segment contains a segment link */ |
static int has_segment_link(mstate m, msegmentptr ss) { |
msegmentptr sp = &m->seg; |
for (;;) { |
if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size) |
return 1; |
if ((sp = sp->next) == 0) |
return 0; |
} |
} |
#ifndef MORECORE_CANNOT_TRIM |
#define should_trim(M,s) ((s) > (M)->trim_check) |
#else /* MORECORE_CANNOT_TRIM */ |
#define should_trim(M,s) (0) |
#endif /* MORECORE_CANNOT_TRIM */ |
/* |
TOP_FOOT_SIZE is padding at the end of a segment, including space |
that may be needed to place segment records and fenceposts when new |
noncontiguous segments are added. |
*/ |
#define TOP_FOOT_SIZE\ |
(align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE) |
/* ------------------------------- Hooks -------------------------------- */ |
/* |
PREACTION should be defined to return 0 on success, and nonzero on |
failure. If you are not using locking, you can redefine these to do |
anything you like. |
*/ |
#if USE_LOCKS |
/* Ensure locks are initialized */ |
#define GLOBALLY_INITIALIZE() (mparams.page_size == 0 && init_mparams()) |
#define PREACTION(M) ((GLOBALLY_INITIALIZE() || use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0) |
#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); } |
#else /* USE_LOCKS */ |
#ifndef PREACTION |
#define PREACTION(M) (0) |
#endif /* PREACTION */ |
#ifndef POSTACTION |
#define POSTACTION(M) |
#endif /* POSTACTION */ |
#endif /* USE_LOCKS */ |
/* |
CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses. |
USAGE_ERROR_ACTION is triggered on detected bad frees and |
reallocs. The argument p is an address that might have triggered the |
fault. It is ignored by the two predefined actions, but might be |
useful in custom actions that try to help diagnose errors. |
*/ |
#if PROCEED_ON_ERROR |
/* A count of the number of corruption errors causing resets */ |
int malloc_corruption_error_count; |
/* default corruption action */ |
static void reset_on_error(mstate m); |
#define CORRUPTION_ERROR_ACTION(m) reset_on_error(m) |
#define USAGE_ERROR_ACTION(m, p) |
#else /* PROCEED_ON_ERROR */ |
#ifndef CORRUPTION_ERROR_ACTION |
#define CORRUPTION_ERROR_ACTION(m) ABORT |
#endif /* CORRUPTION_ERROR_ACTION */ |
#ifndef USAGE_ERROR_ACTION |
#define USAGE_ERROR_ACTION(m,p) ABORT |
#endif /* USAGE_ERROR_ACTION */ |
#endif /* PROCEED_ON_ERROR */ |
/* -------------------------- Debugging setup ---------------------------- */ |
#if ! DEBUG |
#define check_free_chunk(M,P) |
#define check_inuse_chunk(M,P) |
#define check_malloced_chunk(M,P,N) |
#define check_mmapped_chunk(M,P) |
#define check_malloc_state(M) |
#define check_top_chunk(M,P) |
#else /* DEBUG */ |
#define check_free_chunk(M,P) do_check_free_chunk(M,P) |
#define check_inuse_chunk(M,P) do_check_inuse_chunk(M,P) |
#define check_top_chunk(M,P) do_check_top_chunk(M,P) |
#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N) |
#define check_mmapped_chunk(M,P) do_check_mmapped_chunk(M,P) |
#define check_malloc_state(M) do_check_malloc_state(M) |
static void do_check_any_chunk(mstate m, mchunkptr p); |
static void do_check_top_chunk(mstate m, mchunkptr p); |
static void do_check_mmapped_chunk(mstate m, mchunkptr p); |
static void do_check_inuse_chunk(mstate m, mchunkptr p); |
static void do_check_free_chunk(mstate m, mchunkptr p); |
static void do_check_malloced_chunk(mstate m, void* mem, size_t s); |
static void do_check_tree(mstate m, tchunkptr t); |
static void do_check_treebin(mstate m, bindex_t i); |
static void do_check_smallbin(mstate m, bindex_t i); |
static void do_check_malloc_state(mstate m); |
static int bin_find(mstate m, mchunkptr x); |
static size_t traverse_and_check(mstate m); |
#endif /* DEBUG */ |
/* ---------------------------- Indexing Bins ---------------------------- */ |
#define is_small(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS) |
#define small_index(s) ((s) >> SMALLBIN_SHIFT) |
#define small_index2size(i) ((i) << SMALLBIN_SHIFT) |
#define MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE)) |
/* addressing by index. See above about smallbin repositioning */ |
#define smallbin_at(M, i) ((sbinptr)((char*)&((M)->smallbins[(i)<<1]))) |
#define treebin_at(M,i) (&((M)->treebins[i])) |
/* assign tree index for size S to variable I */ |
#if defined(__GNUC__) && defined(i386) |
#define compute_tree_index(S, I)\ |
{\ |
size_t X = S >> TREEBIN_SHIFT;\ |
if (X == 0)\ |
I = 0;\ |
else if (X > 0xFFFF)\ |
I = NTREEBINS-1;\ |
else {\ |
unsigned int K;\ |
asm("bsrl %1,%0\n\t" : "=r" (K) : "rm" (X));\ |
I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ |
}\ |
} |
#else /* GNUC */ |
#define compute_tree_index(S, I)\ |
{\ |
size_t X = S >> TREEBIN_SHIFT;\ |
if (X == 0)\ |
I = 0;\ |
else if (X > 0xFFFF)\ |
I = NTREEBINS-1;\ |
else {\ |
unsigned int Y = (unsigned int)X;\ |
unsigned int N = ((Y - 0x100) >> 16) & 8;\ |
unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\ |
N += K;\ |
N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\ |
K = 14 - N + ((Y <<= K) >> 15);\ |
I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\ |
}\ |
} |
#endif /* GNUC */ |
/* Bit representing maximum resolved size in a treebin at i */ |
#define bit_for_tree_index(i) \ |
(i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2) |
/* Shift placing maximum resolved bit in a treebin at i as sign bit */ |
#define leftshift_for_tree_index(i) \ |
((i == NTREEBINS-1)? 0 : \ |
((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2))) |
/* The size of the smallest chunk held in bin with index i */ |
#define minsize_for_tree_index(i) \ |
((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) | \ |
(((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1))) |
/* ------------------------ Operations on bin maps ----------------------- */ |
/* bit corresponding to given index */ |
#define idx2bit(i) ((binmap_t)(1) << (i)) |
/* Mark/Clear bits with given index */ |
#define mark_smallmap(M,i) ((M)->smallmap |= idx2bit(i)) |
#define clear_smallmap(M,i) ((M)->smallmap &= ~idx2bit(i)) |
#define smallmap_is_marked(M,i) ((M)->smallmap & idx2bit(i)) |
#define mark_treemap(M,i) ((M)->treemap |= idx2bit(i)) |
#define clear_treemap(M,i) ((M)->treemap &= ~idx2bit(i)) |
#define treemap_is_marked(M,i) ((M)->treemap & idx2bit(i)) |
/* index corresponding to given bit */ |
#if defined(__GNUC__) && defined(i386) |
#define compute_bit2idx(X, I)\ |
{\ |
unsigned int J;\ |
asm("bsfl %1,%0\n\t" : "=r" (J) : "rm" (X));\ |
I = (bindex_t)J;\ |
} |
#else /* GNUC */ |
#if USE_BUILTIN_FFS |
#define compute_bit2idx(X, I) I = ffs(X)-1 |
#else /* USE_BUILTIN_FFS */ |
#define compute_bit2idx(X, I)\ |
{\ |
unsigned int Y = X - 1;\ |
unsigned int K = Y >> (16-4) & 16;\ |
unsigned int N = K; Y >>= K;\ |
N += K = Y >> (8-3) & 8; Y >>= K;\ |
N += K = Y >> (4-2) & 4; Y >>= K;\ |
N += K = Y >> (2-1) & 2; Y >>= K;\ |
N += K = Y >> (1-0) & 1; Y >>= K;\ |
I = (bindex_t)(N + Y);\ |
} |
#endif /* USE_BUILTIN_FFS */ |
#endif /* GNUC */ |
/* isolate the least set bit of a bitmap */ |
#define least_bit(x) ((x) & -(x)) |
/* mask with all bits to left of least bit of x on */ |
#define left_bits(x) ((x<<1) | -(x<<1)) |
/* mask with all bits to left of or equal to least bit of x on */ |
#define same_or_left_bits(x) ((x) | -(x)) |
/* ----------------------- Runtime Check Support ------------------------- */ |
/* |
For security, the main invariant is that malloc/free/etc never |
writes to a static address other than malloc_state, unless static |
malloc_state itself has been corrupted, which cannot occur via |
malloc (because of these checks). In essence this means that we |
believe all pointers, sizes, maps etc held in malloc_state, but |
check all of those linked or offsetted from other embedded data |
structures. These checks are interspersed with main code in a way |
that tends to minimize their run-time cost. |
When FOOTERS is defined, in addition to range checking, we also |
verify footer fields of inuse chunks, which can be used guarantee |
that the mstate controlling malloc/free is intact. This is a |
streamlined version of the approach described by William Robertson |
et al in "Run-time Detection of Heap-based Overflows" LISA'03 |
http://www.usenix.org/events/lisa03/tech/robertson.html The footer |
of an inuse chunk holds the xor of its mstate and a random seed, |
that is checked upon calls to free() and realloc(). This is |
(probablistically) unguessable from outside the program, but can be |
computed by any code successfully malloc'ing any chunk, so does not |
itself provide protection against code that has already broken |
security through some other means. Unlike Robertson et al, we |
always dynamically check addresses of all offset chunks (previous, |
next, etc). This turns out to be cheaper than relying on hashes. |
*/ |
#if !INSECURE |
/* Check if address a is at least as high as any from MORECORE or MMAP */ |
#define ok_address(M, a) ((char*)(a) >= (M)->least_addr) |
/* Check if address of next chunk n is higher than base chunk p */ |
#define ok_next(p, n) ((char*)(p) < (char*)(n)) |
/* Check if p has its cinuse bit on */ |
#define ok_cinuse(p) cinuse(p) |
/* Check if p has its pinuse bit on */ |
#define ok_pinuse(p) pinuse(p) |
#else /* !INSECURE */ |
#define ok_address(M, a) (1) |
#define ok_next(b, n) (1) |
#define ok_cinuse(p) (1) |
#define ok_pinuse(p) (1) |
#endif /* !INSECURE */ |
#if (FOOTERS && !INSECURE) |
/* Check if (alleged) mstate m has expected magic field */ |
#define ok_magic(M) ((M)->magic == mparams.magic) |
#else /* (FOOTERS && !INSECURE) */ |
#define ok_magic(M) (1) |
#endif /* (FOOTERS && !INSECURE) */ |
/* In gcc, use __builtin_expect to minimize impact of checks */ |
#if !INSECURE |
#if defined(__GNUC__) && __GNUC__ >= 3 |
#define RTCHECK(e) __builtin_expect(e, 1) |
#else /* GNUC */ |
#define RTCHECK(e) (e) |
#endif /* GNUC */ |
#else /* !INSECURE */ |
#define RTCHECK(e) (1) |
#endif /* !INSECURE */ |
/* macros to set up inuse chunks with or without footers */ |
#if !FOOTERS |
#define mark_inuse_foot(M,p,s) |
/* Set cinuse bit and pinuse bit of next chunk */ |
#define set_inuse(M,p,s)\ |
((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ |
((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) |
/* Set cinuse and pinuse of this chunk and pinuse of next chunk */ |
#define set_inuse_and_pinuse(M,p,s)\ |
((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ |
((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) |
/* Set size, cinuse and pinuse bit of this chunk */ |
#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ |
((p)->head = (s|PINUSE_BIT|CINUSE_BIT)) |
#else /* FOOTERS */ |
/* Set foot of inuse chunk to be xor of mstate and seed */ |
#define mark_inuse_foot(M,p,s)\ |
(((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic)) |
#define get_mstate_for(p)\ |
((mstate)(((mchunkptr)((char*)(p) +\ |
(chunksize(p))))->prev_foot ^ mparams.magic)) |
#define set_inuse(M,p,s)\ |
((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ |
(((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \ |
mark_inuse_foot(M,p,s)) |
#define set_inuse_and_pinuse(M,p,s)\ |
((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ |
(((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\ |
mark_inuse_foot(M,p,s)) |
#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ |
((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ |
mark_inuse_foot(M, p, s)) |
#endif /* !FOOTERS */ |
/* ---------------------------- setting mparams -------------------------- */ |
/* Initialize mparams */ |
static int init_mparams(void) { |
if (mparams.page_size == 0) { |
size_t s; |
mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD; |
mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD; |
#if MORECORE_CONTIGUOUS |
mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT; |
#else /* MORECORE_CONTIGUOUS */ |
mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT; |
#endif /* MORECORE_CONTIGUOUS */ |
#if (FOOTERS && !INSECURE) |
{ |
#if USE_DEV_RANDOM |
int fd; |
unsigned char buf[sizeof(size_t)]; |
/* Try to use /dev/urandom, else fall back on using time */ |
if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 && |
read(fd, buf, sizeof(buf)) == sizeof(buf)) { |
s = *((size_t *) buf); |
close(fd); |
} |
else |
#endif /* USE_DEV_RANDOM */ |
s = (size_t)(time(0) ^ (size_t)0x55555555U); |
s |= (size_t)8U; /* ensure nonzero */ |
s &= ~(size_t)7U; /* improve chances of fault for bad values */ |
} |
#else /* (FOOTERS && !INSECURE) */ |
s = (size_t)0x58585858U; |
#endif /* (FOOTERS && !INSECURE) */ |
ACQUIRE_MAGIC_INIT_LOCK(); |
if (mparams.magic == 0) { |
mparams.magic = s; |
/* Set up lock for main malloc area */ |
INITIAL_LOCK(&gm->mutex); |
gm->mflags = mparams.default_mflags; |
} |
RELEASE_MAGIC_INIT_LOCK(); |
#ifndef WIN32 |
mparams.page_size = malloc_getpagesize; |
mparams.granularity = ((DEFAULT_GRANULARITY != 0)? |
DEFAULT_GRANULARITY : mparams.page_size); |
#else /* WIN32 */ |
{ |
SYSTEM_INFO system_info; |
GetSystemInfo(&system_info); |
mparams.page_size = system_info.dwPageSize; |
mparams.granularity = system_info.dwAllocationGranularity; |
} |
#endif /* WIN32 */ |
/* Sanity-check configuration: |
size_t must be unsigned and as wide as pointer type. |
ints must be at least 4 bytes. |
alignment must be at least 8. |
Alignment, min chunk size, and page size must all be powers of 2. |
*/ |
if ((sizeof(size_t) != sizeof(char*)) || |
(MAX_SIZE_T < MIN_CHUNK_SIZE) || |
(sizeof(int) < 4) || |
(MALLOC_ALIGNMENT < (size_t)8U) || |
((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-SIZE_T_ONE)) != 0) || |
((MCHUNK_SIZE & (MCHUNK_SIZE-SIZE_T_ONE)) != 0) || |
((mparams.granularity & (mparams.granularity-SIZE_T_ONE)) != 0) || |
((mparams.page_size & (mparams.page_size-SIZE_T_ONE)) != 0)) |
ABORT; |
} |
return 0; |
} |
/* support for mallopt */ |
static int change_mparam(int param_number, int value) { |
size_t val = (size_t)value; |
init_mparams(); |
switch(param_number) { |
case M_TRIM_THRESHOLD: |
mparams.trim_threshold = val; |
return 1; |
case M_GRANULARITY: |
if (val >= mparams.page_size && ((val & (val-1)) == 0)) { |
mparams.granularity = val; |
return 1; |
} |
else |
return 0; |
case M_MMAP_THRESHOLD: |
mparams.mmap_threshold = val; |
return 1; |
default: |
return 0; |
} |
} |
#if DEBUG |
/* ------------------------- Debugging Support --------------------------- */ |
/* Check properties of any chunk, whether free, inuse, mmapped etc */ |
static void do_check_any_chunk(mstate m, mchunkptr p) { |
assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); |
assert(ok_address(m, p)); |
} |
/* Check properties of top chunk */ |
static void do_check_top_chunk(mstate m, mchunkptr p) { |
msegmentptr sp = segment_holding(m, (char*)p); |
size_t sz = chunksize(p); |
assert(sp != 0); |
assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); |
assert(ok_address(m, p)); |
assert(sz == m->topsize); |
assert(sz > 0); |
assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE); |
assert(pinuse(p)); |
assert(!next_pinuse(p)); |
} |
/* Check properties of (inuse) mmapped chunks */ |
static void do_check_mmapped_chunk(mstate m, mchunkptr p) { |
size_t sz = chunksize(p); |
size_t len = (sz + (p->prev_foot & ~IS_MMAPPED_BIT) + MMAP_FOOT_PAD); |
assert(is_mmapped(p)); |
assert(use_mmap(m)); |
assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); |
assert(ok_address(m, p)); |
assert(!is_small(sz)); |
assert((len & (mparams.page_size-SIZE_T_ONE)) == 0); |
assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD); |
assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0); |
} |
/* Check properties of inuse chunks */ |
static void do_check_inuse_chunk(mstate m, mchunkptr p) { |
do_check_any_chunk(m, p); |
assert(cinuse(p)); |
assert(next_pinuse(p)); |
/* If not pinuse and not mmapped, previous chunk has OK offset */ |
assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p); |
if (is_mmapped(p)) |
do_check_mmapped_chunk(m, p); |
} |
/* Check properties of free chunks */ |
static void do_check_free_chunk(mstate m, mchunkptr p) { |
size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT); |
mchunkptr next = chunk_plus_offset(p, sz); |
do_check_any_chunk(m, p); |
assert(!cinuse(p)); |
assert(!next_pinuse(p)); |
assert (!is_mmapped(p)); |
if (p != m->dv && p != m->top) { |
if (sz >= MIN_CHUNK_SIZE) { |
assert((sz & CHUNK_ALIGN_MASK) == 0); |
assert(is_aligned(chunk2mem(p))); |
assert(next->prev_foot == sz); |
assert(pinuse(p)); |
assert (next == m->top || cinuse(next)); |
assert(p->fd->bk == p); |
assert(p->bk->fd == p); |
} |
else /* markers are always of size SIZE_T_SIZE */ |
assert(sz == SIZE_T_SIZE); |
} |
} |
/* Check properties of malloced chunks at the point they are malloced */ |
static void do_check_malloced_chunk(mstate m, void* mem, size_t s) { |
if (mem != 0) { |
mchunkptr p = mem2chunk(mem); |
size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT); |
do_check_inuse_chunk(m, p); |
assert((sz & CHUNK_ALIGN_MASK) == 0); |
assert(sz >= MIN_CHUNK_SIZE); |
assert(sz >= s); |
/* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */ |
assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE)); |
} |
} |
/* Check a tree and its subtrees. */ |
static void do_check_tree(mstate m, tchunkptr t) { |
tchunkptr head = 0; |
tchunkptr u = t; |
bindex_t tindex = t->index; |
size_t tsize = chunksize(t); |
bindex_t idx; |
compute_tree_index(tsize, idx); |
assert(tindex == idx); |
assert(tsize >= MIN_LARGE_SIZE); |
assert(tsize >= minsize_for_tree_index(idx)); |
assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1)))); |
do { /* traverse through chain of same-sized nodes */ |
do_check_any_chunk(m, ((mchunkptr)u)); |
assert(u->index == tindex); |
assert(chunksize(u) == tsize); |
assert(!cinuse(u)); |
assert(!next_pinuse(u)); |
assert(u->fd->bk == u); |
assert(u->bk->fd == u); |
if (u->parent == 0) { |
assert(u->child[0] == 0); |
assert(u->child[1] == 0); |
} |
else { |
assert(head == 0); /* only one node on chain has parent */ |
head = u; |
assert(u->parent != u); |
assert (u->parent->child[0] == u || |
u->parent->child[1] == u || |
*((tbinptr*)(u->parent)) == u); |
if (u->child[0] != 0) { |
assert(u->child[0]->parent == u); |
assert(u->child[0] != u); |
do_check_tree(m, u->child[0]); |
} |
if (u->child[1] != 0) { |
assert(u->child[1]->parent == u); |
assert(u->child[1] != u); |
do_check_tree(m, u->child[1]); |
} |
if (u->child[0] != 0 && u->child[1] != 0) { |
assert(chunksize(u->child[0]) < chunksize(u->child[1])); |
} |
} |
u = u->fd; |
} while (u != t); |
assert(head != 0); |
} |
/* Check all the chunks in a treebin. */ |
static void do_check_treebin(mstate m, bindex_t i) { |
tbinptr* tb = treebin_at(m, i); |
tchunkptr t = *tb; |
int empty = (m->treemap & (1U << i)) == 0; |
if (t == 0) |
assert(empty); |
if (!empty) |
do_check_tree(m, t); |
} |
/* Check all the chunks in a smallbin. */ |
static void do_check_smallbin(mstate m, bindex_t i) { |
sbinptr b = smallbin_at(m, i); |
mchunkptr p = b->bk; |
unsigned int empty = (m->smallmap & (1U << i)) == 0; |
if (p == b) |
assert(empty); |
if (!empty) { |
for (; p != b; p = p->bk) { |
size_t size = chunksize(p); |
mchunkptr q; |
/* each chunk claims to be free */ |
do_check_free_chunk(m, p); |
/* chunk belongs in bin */ |
assert(small_index(size) == i); |
assert(p->bk == b || chunksize(p->bk) == chunksize(p)); |
/* chunk is followed by an inuse chunk */ |
q = next_chunk(p); |
if (q->head != FENCEPOST_HEAD) |
do_check_inuse_chunk(m, q); |
} |
} |
} |
/* Find x in a bin. Used in other check functions. */ |
static int bin_find(mstate m, mchunkptr x) { |
size_t size = chunksize(x); |
if (is_small(size)) { |
bindex_t sidx = small_index(size); |
sbinptr b = smallbin_at(m, sidx); |
if (smallmap_is_marked(m, sidx)) { |
mchunkptr p = b; |
do { |
if (p == x) |
return 1; |
} while ((p = p->fd) != b); |
} |
} |
else { |
bindex_t tidx; |
compute_tree_index(size, tidx); |
if (treemap_is_marked(m, tidx)) { |
tchunkptr t = *treebin_at(m, tidx); |
size_t sizebits = size << leftshift_for_tree_index(tidx); |
while (t != 0 && chunksize(t) != size) { |
t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; |
sizebits <<= 1; |
} |
if (t != 0) { |
tchunkptr u = t; |
do { |
if (u == (tchunkptr)x) |
return 1; |
} while ((u = u->fd) != t); |
} |
} |
} |
return 0; |
} |
/* Traverse each chunk and check it; return total */ |
static size_t traverse_and_check(mstate m) { |
size_t sum = 0; |
if (is_initialized(m)) { |
msegmentptr s = &m->seg; |
sum += m->topsize + TOP_FOOT_SIZE; |
while (s != 0) { |
mchunkptr q = align_as_chunk(s->base); |
mchunkptr lastq = 0; |
assert(pinuse(q)); |
while (segment_holds(s, q) && |
q != m->top && q->head != FENCEPOST_HEAD) { |
sum += chunksize(q); |
if (cinuse(q)) { |
assert(!bin_find(m, q)); |
do_check_inuse_chunk(m, q); |
} |
else { |
assert(q == m->dv || bin_find(m, q)); |
assert(lastq == 0 || cinuse(lastq)); /* Not 2 consecutive free */ |
do_check_free_chunk(m, q); |
} |
lastq = q; |
q = next_chunk(q); |
} |
s = s->next; |
} |
} |
return sum; |
} |
/* Check all properties of malloc_state. */ |
static void do_check_malloc_state(mstate m) { |
bindex_t i; |
size_t total; |
/* check bins */ |
for (i = 0; i < NSMALLBINS; ++i) |
do_check_smallbin(m, i); |
for (i = 0; i < NTREEBINS; ++i) |
do_check_treebin(m, i); |
if (m->dvsize != 0) { /* check dv chunk */ |
do_check_any_chunk(m, m->dv); |
assert(m->dvsize == chunksize(m->dv)); |
assert(m->dvsize >= MIN_CHUNK_SIZE); |
assert(bin_find(m, m->dv) == 0); |
} |
if (m->top != 0) { /* check top chunk */ |
do_check_top_chunk(m, m->top); |
assert(m->topsize == chunksize(m->top)); |
assert(m->topsize > 0); |
assert(bin_find(m, m->top) == 0); |
} |
total = traverse_and_check(m); |
assert(total <= m->footprint); |
assert(m->footprint <= m->max_footprint); |
} |
#endif /* DEBUG */ |
/* ----------------------------- statistics ------------------------------ */ |
#if !NO_MALLINFO |
static struct mallinfo internal_mallinfo(mstate m) { |
struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; |
if (!PREACTION(m)) { |
check_malloc_state(m); |
if (is_initialized(m)) { |
size_t nfree = SIZE_T_ONE; /* top always free */ |
size_t mfree = m->topsize + TOP_FOOT_SIZE; |
size_t sum = mfree; |
msegmentptr s = &m->seg; |
while (s != 0) { |
mchunkptr q = align_as_chunk(s->base); |
while (segment_holds(s, q) && |
q != m->top && q->head != FENCEPOST_HEAD) { |
size_t sz = chunksize(q); |
sum += sz; |
if (!cinuse(q)) { |
mfree += sz; |
++nfree; |
} |
q = next_chunk(q); |
} |
s = s->next; |
} |
nm.arena = sum; |
nm.ordblks = nfree; |
nm.hblkhd = m->footprint - sum; |
nm.usmblks = m->max_footprint; |
nm.uordblks = m->footprint - mfree; |
nm.fordblks = mfree; |
nm.keepcost = m->topsize; |
} |
POSTACTION(m); |
} |
return nm; |
} |
#endif /* !NO_MALLINFO */ |
static void internal_malloc_stats(mstate m) { |
if (!PREACTION(m)) { |
size_t maxfp = 0; |
size_t fp = 0; |
size_t used = 0; |
check_malloc_state(m); |
if (is_initialized(m)) { |
msegmentptr s = &m->seg; |
maxfp = m->max_footprint; |
fp = m->footprint; |
used = fp - (m->topsize + TOP_FOOT_SIZE); |
while (s != 0) { |
mchunkptr q = align_as_chunk(s->base); |
while (segment_holds(s, q) && |
q != m->top && q->head != FENCEPOST_HEAD) { |
if (!cinuse(q)) |
used -= chunksize(q); |
q = next_chunk(q); |
} |
s = s->next; |
} |
} |
fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp)); |
fprintf(stderr, "system bytes = %10lu\n", (unsigned long)(fp)); |
fprintf(stderr, "in use bytes = %10lu\n", (unsigned long)(used)); |
POSTACTION(m); |
} |
} |
/* ----------------------- Operations on smallbins ----------------------- */ |
/* |
Various forms of linking and unlinking are defined as macros. Even |
the ones for trees, which are very long but have very short typical |
paths. This is ugly but reduces reliance on inlining support of |
compilers. |
*/ |
/* Link a free chunk into a smallbin */ |
#define insert_small_chunk(M, P, S) {\ |
bindex_t I = small_index(S);\ |
mchunkptr B = smallbin_at(M, I);\ |
mchunkptr F = B;\ |
assert(S >= MIN_CHUNK_SIZE);\ |
if (!smallmap_is_marked(M, I))\ |
mark_smallmap(M, I);\ |
else if (RTCHECK(ok_address(M, B->fd)))\ |
F = B->fd;\ |
else {\ |
CORRUPTION_ERROR_ACTION(M);\ |
}\ |
B->fd = P;\ |
F->bk = P;\ |
P->fd = F;\ |
P->bk = B;\ |
} |
/* Unlink a chunk from a smallbin */ |
#define unlink_small_chunk(M, P, S) {\ |
mchunkptr F = P->fd;\ |
mchunkptr B = P->bk;\ |
bindex_t I = small_index(S);\ |
assert(P != B);\ |
assert(P != F);\ |
assert(chunksize(P) == small_index2size(I));\ |
if (F == B)\ |
clear_smallmap(M, I);\ |
else if (RTCHECK((F == smallbin_at(M,I) || ok_address(M, F)) &&\ |
(B == smallbin_at(M,I) || ok_address(M, B)))) {\ |
F->bk = B;\ |
B->fd = F;\ |
}\ |
else {\ |
CORRUPTION_ERROR_ACTION(M);\ |
}\ |
} |
/* Unlink the first chunk from a smallbin */ |
#define unlink_first_small_chunk(M, B, P, I) {\ |
mchunkptr F = P->fd;\ |
assert(P != B);\ |
assert(P != F);\ |
assert(chunksize(P) == small_index2size(I));\ |
if (B == F)\ |
clear_smallmap(M, I);\ |
else if (RTCHECK(ok_address(M, F))) {\ |
B->fd = F;\ |
F->bk = B;\ |
}\ |
else {\ |
CORRUPTION_ERROR_ACTION(M);\ |
}\ |
} |
/* Replace dv node, binning the old one */ |
/* Used only when dvsize known to be small */ |
#define replace_dv(M, P, S) {\ |
size_t DVS = M->dvsize;\ |
if (DVS != 0) {\ |
mchunkptr DV = M->dv;\ |
assert(is_small(DVS));\ |
insert_small_chunk(M, DV, DVS);\ |
}\ |
M->dvsize = S;\ |
M->dv = P;\ |
} |
/* ------------------------- Operations on trees ------------------------- */ |
/* Insert chunk into tree */ |
#define insert_large_chunk(M, X, S) {\ |
tbinptr* H;\ |
bindex_t I;\ |
compute_tree_index(S, I);\ |
H = treebin_at(M, I);\ |
X->index = I;\ |
X->child[0] = X->child[1] = 0;\ |
if (!treemap_is_marked(M, I)) {\ |
mark_treemap(M, I);\ |
*H = X;\ |
X->parent = (tchunkptr)H;\ |
X->fd = X->bk = X;\ |
}\ |
else {\ |
tchunkptr T = *H;\ |
size_t K = S << leftshift_for_tree_index(I);\ |
for (;;) {\ |
if (chunksize(T) != S) {\ |
tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\ |
K <<= 1;\ |
if (*C != 0)\ |
T = *C;\ |
else if (RTCHECK(ok_address(M, C))) {\ |
*C = X;\ |
X->parent = T;\ |
X->fd = X->bk = X;\ |
break;\ |
}\ |
else {\ |
CORRUPTION_ERROR_ACTION(M);\ |
break;\ |
}\ |
}\ |
else {\ |
tchunkptr F = T->fd;\ |
if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\ |
T->fd = F->bk = X;\ |
X->fd = F;\ |
X->bk = T;\ |
X->parent = 0;\ |
break;\ |
}\ |
else {\ |
CORRUPTION_ERROR_ACTION(M);\ |
break;\ |
}\ |
}\ |
}\ |
}\ |
} |
/* |
Unlink steps: |
1. If x is a chained node, unlink it from its same-sized fd/bk links |
and choose its bk node as its replacement. |
2. If x was the last node of its size, but not a leaf node, it must |
be replaced with a leaf node (not merely one with an open left or |
right), to make sure that lefts and rights of descendents |
correspond properly to bit masks. We use the rightmost descendent |
of x. We could use any other leaf, but this is easy to locate and |
tends to counteract removal of leftmosts elsewhere, and so keeps |
paths shorter than minimally guaranteed. This doesn't loop much |
because on average a node in a tree is near the bottom. |
3. If x is the base of a chain (i.e., has parent links) relink |
x's parent and children to x's replacement (or null if none). |
*/ |
#define unlink_large_chunk(M, X) {\ |
tchunkptr XP = X->parent;\ |
tchunkptr R;\ |
if (X->bk != X) {\ |
tchunkptr F = X->fd;\ |
R = X->bk;\ |
if (RTCHECK(ok_address(M, F))) {\ |
F->bk = R;\ |
R->fd = F;\ |
}\ |
else {\ |
CORRUPTION_ERROR_ACTION(M);\ |
}\ |
}\ |
else {\ |
tchunkptr* RP;\ |
if (((R = *(RP = &(X->child[1]))) != 0) ||\ |
((R = *(RP = &(X->child[0]))) != 0)) {\ |
tchunkptr* CP;\ |
while ((*(CP = &(R->child[1])) != 0) ||\ |
(*(CP = &(R->child[0])) != 0)) {\ |
R = *(RP = CP);\ |
}\ |
if (RTCHECK(ok_address(M, RP)))\ |
*RP = 0;\ |
else {\ |
CORRUPTION_ERROR_ACTION(M);\ |
}\ |
}\ |
}\ |
if (XP != 0) {\ |
tbinptr* H = treebin_at(M, X->index);\ |
if (X == *H) {\ |
if ((*H = R) == 0) \ |
clear_treemap(M, X->index);\ |
}\ |
else if (RTCHECK(ok_address(M, XP))) {\ |
if (XP->child[0] == X) \ |
XP->child[0] = R;\ |
else \ |
XP->child[1] = R;\ |
}\ |
else\ |
CORRUPTION_ERROR_ACTION(M);\ |
if (R != 0) {\ |
if (RTCHECK(ok_address(M, R))) {\ |
tchunkptr C0, C1;\ |
R->parent = XP;\ |
if ((C0 = X->child[0]) != 0) {\ |
if (RTCHECK(ok_address(M, C0))) {\ |
R->child[0] = C0;\ |
C0->parent = R;\ |
}\ |
else\ |
CORRUPTION_ERROR_ACTION(M);\ |
}\ |
if ((C1 = X->child[1]) != 0) {\ |
if (RTCHECK(ok_address(M, C1))) {\ |
R->child[1] = C1;\ |
C1->parent = R;\ |
}\ |
else\ |
CORRUPTION_ERROR_ACTION(M);\ |
}\ |
}\ |
else\ |
CORRUPTION_ERROR_ACTION(M);\ |
}\ |
}\ |
} |
/* Relays to large vs small bin operations */ |
#define insert_chunk(M, P, S)\ |
if (is_small(S)) insert_small_chunk(M, P, S)\ |
else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); } |
#define unlink_chunk(M, P, S)\ |
if (is_small(S)) unlink_small_chunk(M, P, S)\ |
else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); } |
/* Relays to internal calls to malloc/free from realloc, memalign etc */ |
#if ONLY_MSPACES |
#define internal_malloc(m, b) mspace_malloc(m, b) |
#define internal_free(m, mem) mspace_free(m,mem); |
#else /* ONLY_MSPACES */ |
#if MSPACES |
#define internal_malloc(m, b)\ |
(m == gm)? dlmalloc(b) : mspace_malloc(m, b) |
#define internal_free(m, mem)\ |
if (m == gm) dlfree(mem); else mspace_free(m,mem); |
#else /* MSPACES */ |
#define internal_malloc(m, b) dlmalloc(b) |
#define internal_free(m, mem) dlfree(mem) |
#endif /* MSPACES */ |
#endif /* ONLY_MSPACES */ |
/* ----------------------- Direct-mmapping chunks ----------------------- */ |
/* |
Directly mmapped chunks are set up with an offset to the start of |
the mmapped region stored in the prev_foot field of the chunk. This |
allows reconstruction of the required argument to MUNMAP when freed, |
and also allows adjustment of the returned chunk to meet alignment |
requirements (especially in memalign). There is also enough space |
allocated to hold a fake next chunk of size SIZE_T_SIZE to maintain |
the PINUSE bit so frees can be checked. |
*/ |
/* Malloc using mmap */ |
static void* mmap_alloc(mstate m, size_t nb) { |
size_t mmsize = granularity_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); |
if (mmsize > nb) { /* Check for wrap around 0 */ |
char* mm = (char*)(DIRECT_MMAP(mmsize)); |
if (mm != CMFAIL) { |
size_t offset = align_offset(chunk2mem(mm)); |
size_t psize = mmsize - offset - MMAP_FOOT_PAD; |
mchunkptr p = (mchunkptr)(mm + offset); |
p->prev_foot = offset | IS_MMAPPED_BIT; |
(p)->head = (psize|CINUSE_BIT); |
mark_inuse_foot(m, p, psize); |
chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD; |
chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0; |
if (mm < m->least_addr) |
m->least_addr = mm; |
if ((m->footprint += mmsize) > m->max_footprint) |
m->max_footprint = m->footprint; |
assert(is_aligned(chunk2mem(p))); |
check_mmapped_chunk(m, p); |
return chunk2mem(p); |
} |
} |
return 0; |
} |
/* Realloc using mmap */ |
static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb) { |
size_t oldsize = chunksize(oldp); |
if (is_small(nb)) /* Can't shrink mmap regions below small size */ |
return 0; |
/* Keep old chunk if big enough but not too big */ |
if (oldsize >= nb + SIZE_T_SIZE && |
(oldsize - nb) <= (mparams.granularity << 1)) |
return oldp; |
else { |
size_t offset = oldp->prev_foot & ~IS_MMAPPED_BIT; |
size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD; |
size_t newmmsize = granularity_align(nb + SIX_SIZE_T_SIZES + |
CHUNK_ALIGN_MASK); |
char* cp = (char*)CALL_MREMAP((char*)oldp - offset, |
oldmmsize, newmmsize, 1); |
if (cp != CMFAIL) { |
mchunkptr newp = (mchunkptr)(cp + offset); |
size_t psize = newmmsize - offset - MMAP_FOOT_PAD; |
newp->head = (psize|CINUSE_BIT); |
mark_inuse_foot(m, newp, psize); |
chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD; |
chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0; |
if (cp < m->least_addr) |
m->least_addr = cp; |
if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint) |
m->max_footprint = m->footprint; |
check_mmapped_chunk(m, newp); |
return newp; |
} |
} |
return 0; |
} |
/* -------------------------- mspace management -------------------------- */ |
/* Initialize top chunk and its size */ |
static void init_top(mstate m, mchunkptr p, size_t psize) { |
/* Ensure alignment */ |
size_t offset = align_offset(chunk2mem(p)); |
p = (mchunkptr)((char*)p + offset); |
psize -= offset; |
m->top = p; |
m->topsize = psize; |
p->head = psize | PINUSE_BIT; |
/* set size of fake trailing chunk holding overhead space only once */ |
chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE; |
m->trim_check = mparams.trim_threshold; /* reset on each update */ |
} |
/* Initialize bins for a new mstate that is otherwise zeroed out */ |
static void init_bins(mstate m) { |
/* Establish circular links for smallbins */ |
bindex_t i; |
for (i = 0; i < NSMALLBINS; ++i) { |
sbinptr bin = smallbin_at(m,i); |
bin->fd = bin->bk = bin; |
} |
} |
#if PROCEED_ON_ERROR |
/* default corruption action */ |
static void reset_on_error(mstate m) { |
int i; |
++malloc_corruption_error_count; |
/* Reinitialize fields to forget about all memory */ |
m->smallbins = m->treebins = 0; |
m->dvsize = m->topsize = 0; |
m->seg.base = 0; |
m->seg.size = 0; |
m->seg.next = 0; |
m->top = m->dv = 0; |
for (i = 0; i < NTREEBINS; ++i) |
*treebin_at(m, i) = 0; |
init_bins(m); |
} |
#endif /* PROCEED_ON_ERROR */ |
/* Allocate chunk and prepend remainder with chunk in successor base. */ |
static void* prepend_alloc(mstate m, char* newbase, char* oldbase, |
size_t nb) { |
mchunkptr p = align_as_chunk(newbase); |
mchunkptr oldfirst = align_as_chunk(oldbase); |
size_t psize = (char*)oldfirst - (char*)p; |
mchunkptr q = chunk_plus_offset(p, nb); |
size_t qsize = psize - nb; |
set_size_and_pinuse_of_inuse_chunk(m, p, nb); |
assert((char*)oldfirst > (char*)q); |
assert(pinuse(oldfirst)); |
assert(qsize >= MIN_CHUNK_SIZE); |
/* consolidate remainder with first chunk of old base */ |
if (oldfirst == m->top) { |
size_t tsize = m->topsize += qsize; |
m->top = q; |
q->head = tsize | PINUSE_BIT; |
check_top_chunk(m, q); |
} |
else if (oldfirst == m->dv) { |
size_t dsize = m->dvsize += qsize; |
m->dv = q; |
set_size_and_pinuse_of_free_chunk(q, dsize); |
} |
else { |
if (!cinuse(oldfirst)) { |
size_t nsize = chunksize(oldfirst); |
unlink_chunk(m, oldfirst, nsize); |
oldfirst = chunk_plus_offset(oldfirst, nsize); |
qsize += nsize; |
} |
set_free_with_pinuse(q, qsize, oldfirst); |
insert_chunk(m, q, qsize); |
check_free_chunk(m, q); |
} |
check_malloced_chunk(m, chunk2mem(p), nb); |
return chunk2mem(p); |
} |
/* Add a segment to hold a new noncontiguous region */ |
static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) { |
/* Determine locations and sizes of segment, fenceposts, old top */ |
char* old_top = (char*)m->top; |
msegmentptr oldsp = segment_holding(m, old_top); |
char* old_end = oldsp->base + oldsp->size; |
size_t ssize = pad_request(sizeof(struct malloc_segment)); |
char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK); |
size_t offset = align_offset(chunk2mem(rawsp)); |
char* asp = rawsp + offset; |
char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp; |
mchunkptr sp = (mchunkptr)csp; |
msegmentptr ss = (msegmentptr)(chunk2mem(sp)); |
mchunkptr tnext = chunk_plus_offset(sp, ssize); |
mchunkptr p = tnext; |
int nfences = 0; |
/* reset top to new space */ |
init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); |
/* Set up segment record */ |
assert(is_aligned(ss)); |
set_size_and_pinuse_of_inuse_chunk(m, sp, ssize); |
*ss = m->seg; /* Push current record */ |
m->seg.base = tbase; |
m->seg.size = tsize; |
m->seg.sflags = mmapped; |
m->seg.next = ss; |
/* Insert trailing fenceposts */ |
for (;;) { |
mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE); |
p->head = FENCEPOST_HEAD; |
++nfences; |
if ((char*)(&(nextp->head)) < old_end) |
p = nextp; |
else |
break; |
} |
assert(nfences >= 2); |
/* Insert the rest of old top into a bin as an ordinary free chunk */ |
if (csp != old_top) { |
mchunkptr q = (mchunkptr)old_top; |
size_t psize = csp - old_top; |
mchunkptr tn = chunk_plus_offset(q, psize); |
set_free_with_pinuse(q, psize, tn); |
insert_chunk(m, q, psize); |
} |
check_top_chunk(m, m->top); |
} |
/* -------------------------- System allocation -------------------------- */ |
/* Get memory from system using MORECORE or MMAP */ |
static void* sys_alloc(mstate m, size_t nb) { |
char* tbase = CMFAIL; |
size_t tsize = 0; |
flag_t mmap_flag = 0; |
init_mparams(); |
/* Directly map large chunks */ |
if (use_mmap(m) && nb >= mparams.mmap_threshold) { |
void* mem = mmap_alloc(m, nb); |
if (mem != 0) |
return mem; |
} |
/* |
Try getting memory in any of three ways (in most-preferred to |
least-preferred order): |
1. A call to MORECORE that can normally contiguously extend memory. |
(disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or |
or main space is mmapped or a previous contiguous call failed) |
2. A call to MMAP new space (disabled if not HAVE_MMAP). |
Note that under the default settings, if MORECORE is unable to |
fulfill a request, and HAVE_MMAP is true, then mmap is |
used as a noncontiguous system allocator. This is a useful backup |
strategy for systems with holes in address spaces -- in this case |
sbrk cannot contiguously expand the heap, but mmap may be able to |
find space. |
3. A call to MORECORE that cannot usually contiguously extend memory. |
(disabled if not HAVE_MORECORE) |
*/ |
if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) { |
char* br = CMFAIL; |
msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top); |
size_t asize = 0; |
ACQUIRE_MORECORE_LOCK(); |
if (ss == 0) { /* First time through or recovery */ |
char* base = (char*)CALL_MORECORE(0); |
if (base != CMFAIL) { |
asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE); |
/* Adjust to end on a page boundary */ |
if (!is_page_aligned(base)) |
asize += (page_align((size_t)base) - (size_t)base); |
/* Can't call MORECORE if size is negative when treated as signed */ |
if (asize < HALF_MAX_SIZE_T && |
(br = (char*)(CALL_MORECORE(asize))) == base) { |
tbase = base; |
tsize = asize; |
} |
} |
} |
else { |
/* Subtract out existing available top space from MORECORE request. */ |
asize = granularity_align(nb - m->topsize + TOP_FOOT_SIZE + SIZE_T_ONE); |
/* Use mem here only if it did continuously extend old space */ |
if (asize < HALF_MAX_SIZE_T && |
(br = (char*)(CALL_MORECORE(asize))) == ss->base+ss->size) { |
tbase = br; |
tsize = asize; |
} |
} |
if (tbase == CMFAIL) { /* Cope with partial failure */ |
if (br != CMFAIL) { /* Try to use/extend the space we did get */ |
if (asize < HALF_MAX_SIZE_T && |
asize < nb + TOP_FOOT_SIZE + SIZE_T_ONE) { |
size_t esize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE - asize); |
if (esize < HALF_MAX_SIZE_T) { |
char* end = (char*)CALL_MORECORE(esize); |
if (end != CMFAIL) |
asize += esize; |
else { /* Can't use; try to release */ |
CALL_MORECORE(-asize); |
br = CMFAIL; |
} |
} |
} |
} |
if (br != CMFAIL) { /* Use the space we did get */ |
tbase = br; |
tsize = asize; |
} |
else |
disable_contiguous(m); /* Don't try contiguous path in the future */ |
} |
RELEASE_MORECORE_LOCK(); |
} |
if (HAVE_MMAP && tbase == CMFAIL) { /* Try MMAP */ |
size_t req = nb + TOP_FOOT_SIZE + SIZE_T_ONE; |
size_t rsize = granularity_align(req); |
if (rsize > nb) { /* Fail if wraps around zero */ |
char* mp = (char*)(CALL_MMAP(rsize)); |
if (mp != CMFAIL) { |
tbase = mp; |
tsize = rsize; |
mmap_flag = IS_MMAPPED_BIT; |
} |
} |
} |
if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */ |
size_t asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE); |
if (asize < HALF_MAX_SIZE_T) { |
char* br = CMFAIL; |
char* end = CMFAIL; |
ACQUIRE_MORECORE_LOCK(); |
br = (char*)(CALL_MORECORE(asize)); |
end = (char*)(CALL_MORECORE(0)); |
RELEASE_MORECORE_LOCK(); |
if (br != CMFAIL && end != CMFAIL && br < end) { |
size_t ssize = end - br; |
if (ssize > nb + TOP_FOOT_SIZE) { |
tbase = br; |
tsize = ssize; |
} |
} |
} |
} |
if (tbase != CMFAIL) { |
if ((m->footprint += tsize) > m->max_footprint) |
m->max_footprint = m->footprint; |
if (!is_initialized(m)) { /* first-time initialization */ |
m->seg.base = m->least_addr = tbase; |
m->seg.size = tsize; |
m->seg.sflags = mmap_flag; |
m->magic = mparams.magic; |
init_bins(m); |
if (is_global(m)) |
init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); |
else { |
/* Offset top by embedded malloc_state */ |
mchunkptr mn = next_chunk(mem2chunk(m)); |
init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE); |
} |
} |
else { |
/* Try to merge with an existing segment */ |
msegmentptr sp = &m->seg; |
while (sp != 0 && tbase != sp->base + sp->size) |
sp = sp->next; |
if (sp != 0 && |
!is_extern_segment(sp) && |
(sp->sflags & IS_MMAPPED_BIT) == mmap_flag && |
segment_holds(sp, m->top)) { /* append */ |
sp->size += tsize; |
init_top(m, m->top, m->topsize + tsize); |
} |
else { |
if (tbase < m->least_addr) |
m->least_addr = tbase; |
sp = &m->seg; |
while (sp != 0 && sp->base != tbase + tsize) |
sp = sp->next; |
if (sp != 0 && |
!is_extern_segment(sp) && |
(sp->sflags & IS_MMAPPED_BIT) == mmap_flag) { |
char* oldbase = sp->base; |
sp->base = tbase; |
sp->size += tsize; |
return prepend_alloc(m, tbase, oldbase, nb); |
} |
else |
add_segment(m, tbase, tsize, mmap_flag); |
} |
} |
if (nb < m->topsize) { /* Allocate from new or extended top space */ |
size_t rsize = m->topsize -= nb; |
mchunkptr p = m->top; |
mchunkptr r = m->top = chunk_plus_offset(p, nb); |
r->head = rsize | PINUSE_BIT; |
set_size_and_pinuse_of_inuse_chunk(m, p, nb); |
check_top_chunk(m, m->top); |
check_malloced_chunk(m, chunk2mem(p), nb); |
return chunk2mem(p); |
} |
} |
MALLOC_FAILURE_ACTION; |
return 0; |
} |
/* ----------------------- system deallocation -------------------------- */ |
/* Unmap and unlink any mmapped segments that don't contain used chunks */ |
static size_t release_unused_segments(mstate m) { |
size_t released = 0; |
msegmentptr pred = &m->seg; |
msegmentptr sp = pred->next; |
while (sp != 0) { |
char* base = sp->base; |
size_t size = sp->size; |
msegmentptr next = sp->next; |
if (is_mmapped_segment(sp) && !is_extern_segment(sp)) { |
mchunkptr p = align_as_chunk(base); |
size_t psize = chunksize(p); |
/* Can unmap if first chunk holds entire segment and not pinned */ |
if (!cinuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) { |
tchunkptr tp = (tchunkptr)p; |
assert(segment_holds(sp, (char*)sp)); |
if (p == m->dv) { |
m->dv = 0; |
m->dvsize = 0; |
} |
else { |
unlink_large_chunk(m, tp); |
} |
if (CALL_MUNMAP(base, size) == 0) { |
released += size; |
m->footprint -= size; |
/* unlink obsoleted record */ |
sp = pred; |
sp->next = next; |
} |
else { /* back out if cannot unmap */ |
insert_large_chunk(m, tp, psize); |
} |
} |
} |
pred = sp; |
sp = next; |
} |
return released; |
} |
static int sys_trim(mstate m, size_t pad) { |
size_t released = 0; |
if (pad < MAX_REQUEST && is_initialized(m)) { |
pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */ |
if (m->topsize > pad) { |
/* Shrink top space in granularity-size units, keeping at least one */ |
size_t unit = mparams.granularity; |
size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit - |
SIZE_T_ONE) * unit; |
msegmentptr sp = segment_holding(m, (char*)m->top); |
if (!is_extern_segment(sp)) { |
if (is_mmapped_segment(sp)) { |
if (HAVE_MMAP && |
sp->size >= extra && |
!has_segment_link(m, sp)) { /* can't shrink if pinned */ |
/* Prefer mremap, fall back to munmap */ |
if ((CALL_MREMAP(sp->base, sp->size, sp->size - extra, 0) != MFAIL) || |
(CALL_MUNMAP(sp->base + sp->size - extra, extra) == 0)) { |
released = extra; |
} |
} |
} |
else if (HAVE_MORECORE) { |
if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */ |
extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit; |
ACQUIRE_MORECORE_LOCK(); |
{ |
/* Make sure end of memory is where we last set it. */ |
char* old_br = (char*)(CALL_MORECORE(0)); |
if (old_br == sp->base + sp->size) { |
char* rel_br = (char*)(CALL_MORECORE(-extra)); |
char* new_br = (char*)(CALL_MORECORE(0)); |
if (rel_br != CMFAIL && new_br < old_br) |
released = old_br - new_br; |
} |
} |
RELEASE_MORECORE_LOCK(); |
} |
} |
if (released != 0) { |
sp->size -= released; |
m->footprint -= released; |
init_top(m, m->top, m->topsize - released); |
check_top_chunk(m, m->top); |
} |
} |
/* Unmap any unused mmapped segments */ |
if (HAVE_MMAP) |
released += release_unused_segments(m); |
/* On failure, disable autotrim to avoid repeated failed future calls */ |
if (released == 0) |
m->trim_check = MAX_SIZE_T; |
} |
return (released != 0)? 1 : 0; |
} |
/* ---------------------------- malloc support --------------------------- */ |
/* allocate a large request from the best fitting chunk in a treebin */ |
static void* tmalloc_large(mstate m, size_t nb) { |
tchunkptr v = 0; |
size_t rsize = -nb; /* Unsigned negation */ |
tchunkptr t; |
bindex_t idx; |
compute_tree_index(nb, idx); |
if ((t = *treebin_at(m, idx)) != 0) { |
/* Traverse tree for this bin looking for node with size == nb */ |
size_t sizebits = nb << leftshift_for_tree_index(idx); |
tchunkptr rst = 0; /* The deepest untaken right subtree */ |
for (;;) { |
tchunkptr rt; |
size_t trem = chunksize(t) - nb; |
if (trem < rsize) { |
v = t; |
if ((rsize = trem) == 0) |
break; |
} |
rt = t->child[1]; |
t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; |
if (rt != 0 && rt != t) |
rst = rt; |
if (t == 0) { |
t = rst; /* set t to least subtree holding sizes > nb */ |
break; |
} |
sizebits <<= 1; |
} |
} |
if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */ |
binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap; |
if (leftbits != 0) { |
bindex_t i; |
binmap_t leastbit = least_bit(leftbits); |
compute_bit2idx(leastbit, i); |
t = *treebin_at(m, i); |
} |
} |
while (t != 0) { /* find smallest of tree or subtree */ |
size_t trem = chunksize(t) - nb; |
if (trem < rsize) { |
rsize = trem; |
v = t; |
} |
t = leftmost_child(t); |
} |
/* If dv is a better fit, return 0 so malloc will use it */ |
if (v != 0 && rsize < (size_t)(m->dvsize - nb)) { |
if (RTCHECK(ok_address(m, v))) { /* split */ |
mchunkptr r = chunk_plus_offset(v, nb); |
assert(chunksize(v) == rsize + nb); |
if (RTCHECK(ok_next(v, r))) { |
unlink_large_chunk(m, v); |
if (rsize < MIN_CHUNK_SIZE) |
set_inuse_and_pinuse(m, v, (rsize + nb)); |
else { |
set_size_and_pinuse_of_inuse_chunk(m, v, nb); |
set_size_and_pinuse_of_free_chunk(r, rsize); |
insert_chunk(m, r, rsize); |
} |
return chunk2mem(v); |
} |
} |
CORRUPTION_ERROR_ACTION(m); |
} |
return 0; |
} |
/* allocate a small request from the best fitting chunk in a treebin */ |
static void* tmalloc_small(mstate m, size_t nb) { |
tchunkptr t, v; |
size_t rsize; |
bindex_t i; |
binmap_t leastbit = least_bit(m->treemap); |
compute_bit2idx(leastbit, i); |
v = t = *treebin_at(m, i); |
rsize = chunksize(t) - nb; |
while ((t = leftmost_child(t)) != 0) { |
size_t trem = chunksize(t) - nb; |
if (trem < rsize) { |
rsize = trem; |
v = t; |
} |
} |
if (RTCHECK(ok_address(m, v))) { |
mchunkptr r = chunk_plus_offset(v, nb); |
assert(chunksize(v) == rsize + nb); |
if (RTCHECK(ok_next(v, r))) { |
unlink_large_chunk(m, v); |
if (rsize < MIN_CHUNK_SIZE) |
set_inuse_and_pinuse(m, v, (rsize + nb)); |
else { |
set_size_and_pinuse_of_inuse_chunk(m, v, nb); |
set_size_and_pinuse_of_free_chunk(r, rsize); |
replace_dv(m, r, rsize); |
} |
return chunk2mem(v); |
} |
} |
CORRUPTION_ERROR_ACTION(m); |
return 0; |
} |
/* --------------------------- realloc support --------------------------- */ |
static void* internal_realloc(mstate m, void* oldmem, size_t bytes) { |
if (bytes >= MAX_REQUEST) { |
MALLOC_FAILURE_ACTION; |
return 0; |
} |
if (!PREACTION(m)) { |
mchunkptr oldp = mem2chunk(oldmem); |
size_t oldsize = chunksize(oldp); |
mchunkptr next = chunk_plus_offset(oldp, oldsize); |
mchunkptr newp = 0; |
void* extra = 0; |
/* Try to either shrink or extend into top. Else malloc-copy-free */ |
if (RTCHECK(ok_address(m, oldp) && ok_cinuse(oldp) && |
ok_next(oldp, next) && ok_pinuse(next))) { |
size_t nb = request2size(bytes); |
if (is_mmapped(oldp)) |
newp = mmap_resize(m, oldp, nb); |
else if (oldsize >= nb) { /* already big enough */ |
size_t rsize = oldsize - nb; |
newp = oldp; |
if (rsize >= MIN_CHUNK_SIZE) { |
mchunkptr remainder = chunk_plus_offset(newp, nb); |
set_inuse(m, newp, nb); |
set_inuse(m, remainder, rsize); |
extra = chunk2mem(remainder); |
} |
} |
else if (next == m->top && oldsize + m->topsize > nb) { |
/* Expand into top */ |
size_t newsize = oldsize + m->topsize; |
size_t newtopsize = newsize - nb; |
mchunkptr newtop = chunk_plus_offset(oldp, nb); |
set_inuse(m, oldp, nb); |
newtop->head = newtopsize |PINUSE_BIT; |
m->top = newtop; |
m->topsize = newtopsize; |
newp = oldp; |
} |
} |
else { |
USAGE_ERROR_ACTION(m, oldmem); |
POSTACTION(m); |
return 0; |
} |
POSTACTION(m); |
if (newp != 0) { |
if (extra != 0) { |
internal_free(m, extra); |
} |
check_inuse_chunk(m, newp); |
return chunk2mem(newp); |
} |
else { |
void* newmem = internal_malloc(m, bytes); |
if (newmem != 0) { |
size_t oc = oldsize - overhead_for(oldp); |
memcpy(newmem, oldmem, (oc < bytes)? oc : bytes); |
internal_free(m, oldmem); |
} |
return newmem; |
} |
} |
return 0; |
} |
/* --------------------------- memalign support -------------------------- */ |
static void* internal_memalign(mstate m, size_t alignment, size_t bytes) { |
if (alignment <= MALLOC_ALIGNMENT) /* Can just use malloc */ |
return internal_malloc(m, bytes); |
if (alignment < MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */ |
alignment = MIN_CHUNK_SIZE; |
if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */ |
size_t a = MALLOC_ALIGNMENT << 1; |
while (a < alignment) a <<= 1; |
alignment = a; |
} |
if (bytes >= MAX_REQUEST - alignment) { |
if (m != 0) { /* Test isn't needed but avoids compiler warning */ |
MALLOC_FAILURE_ACTION; |
} |
} |
else { |
size_t nb = request2size(bytes); |
size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD; |
char* mem = (char*)internal_malloc(m, req); |
if (mem != 0) { |
void* leader = 0; |
void* trailer = 0; |
mchunkptr p = mem2chunk(mem); |
if (PREACTION(m)) return 0; |
if ((((size_t)(mem)) % alignment) != 0) { /* misaligned */ |
/* |
Find an aligned spot inside chunk. Since we need to give |
back leading space in a chunk of at least MIN_CHUNK_SIZE, if |
the first calculation places us at a spot with less than |
MIN_CHUNK_SIZE leader, we can move to the next aligned spot. |
We've allocated enough total room so that this is always |
possible. |
*/ |
char* br = (char*)mem2chunk((size_t)(((size_t)(mem + |
alignment - |
SIZE_T_ONE)) & |
-alignment)); |
char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)? |
br : br+alignment; |
mchunkptr newp = (mchunkptr)pos; |
size_t leadsize = pos - (char*)(p); |
size_t newsize = chunksize(p) - leadsize; |
if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */ |
newp->prev_foot = p->prev_foot + leadsize; |
newp->head = (newsize|CINUSE_BIT); |
} |
else { /* Otherwise, give back leader, use the rest */ |
set_inuse(m, newp, newsize); |
set_inuse(m, p, leadsize); |
leader = chunk2mem(p); |
} |
p = newp; |
} |
/* Give back spare room at the end */ |
if (!is_mmapped(p)) { |
size_t size = chunksize(p); |
if (size > nb + MIN_CHUNK_SIZE) { |
size_t remainder_size = size - nb; |
mchunkptr remainder = chunk_plus_offset(p, nb); |
set_inuse(m, p, nb); |
set_inuse(m, remainder, remainder_size); |
trailer = chunk2mem(remainder); |
} |
} |
assert (chunksize(p) >= nb); |
assert((((size_t)(chunk2mem(p))) % alignment) == 0); |
check_inuse_chunk(m, p); |
POSTACTION(m); |
if (leader != 0) { |
internal_free(m, leader); |
} |
if (trailer != 0) { |
internal_free(m, trailer); |
} |
return chunk2mem(p); |
} |
} |
return 0; |
} |
/* ------------------------ comalloc/coalloc support --------------------- */ |
static void** ialloc(mstate m, |
size_t n_elements, |
size_t* sizes, |
int opts, |
void* chunks[]) { |
/* |
This provides common support for independent_X routines, handling |
all of the combinations that can result. |
The opts arg has: |
bit 0 set if all elements are same size (using sizes[0]) |
bit 1 set if elements should be zeroed |
*/ |
size_t element_size; /* chunksize of each element, if all same */ |
size_t contents_size; /* total size of elements */ |
size_t array_size; /* request size of pointer array */ |
void* mem; /* malloced aggregate space */ |
mchunkptr p; /* corresponding chunk */ |
size_t remainder_size; /* remaining bytes while splitting */ |
void** marray; /* either "chunks" or malloced ptr array */ |
mchunkptr array_chunk; /* chunk for malloced ptr array */ |
flag_t was_enabled; /* to disable mmap */ |
size_t size; |
size_t i; |
/* compute array length, if needed */ |
if (chunks != 0) { |
if (n_elements == 0) |
return chunks; /* nothing to do */ |
marray = chunks; |
array_size = 0; |
} |
else { |
/* if empty req, must still return chunk representing empty array */ |
if (n_elements == 0) |
return (void**)internal_malloc(m, 0); |
marray = 0; |
array_size = request2size(n_elements * (sizeof(void*))); |
} |
/* compute total element size */ |
if (opts & 0x1) { /* all-same-size */ |
element_size = request2size(*sizes); |
contents_size = n_elements * element_size; |
} |
else { /* add up all the sizes */ |
element_size = 0; |
contents_size = 0; |
for (i = 0; i != n_elements; ++i) |
contents_size += request2size(sizes[i]); |
} |
size = contents_size + array_size; |
/* |
Allocate the aggregate chunk. First disable direct-mmapping so |
malloc won't use it, since we would not be able to later |
free/realloc space internal to a segregated mmap region. |
*/ |
was_enabled = use_mmap(m); |
disable_mmap(m); |
mem = internal_malloc(m, size - CHUNK_OVERHEAD); |
if (was_enabled) |
enable_mmap(m); |
if (mem == 0) |
return 0; |
if (PREACTION(m)) return 0; |
p = mem2chunk(mem); |
remainder_size = chunksize(p); |
assert(!is_mmapped(p)); |
if (opts & 0x2) { /* optionally clear the elements */ |
memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size); |
} |
/* If not provided, allocate the pointer array as final part of chunk */ |
if (marray == 0) { |
size_t array_chunk_size; |
array_chunk = chunk_plus_offset(p, contents_size); |
array_chunk_size = remainder_size - contents_size; |
marray = (void**) (chunk2mem(array_chunk)); |
set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size); |
remainder_size = contents_size; |
} |
/* split out elements */ |
for (i = 0; ; ++i) { |
marray[i] = chunk2mem(p); |
if (i != n_elements-1) { |
if (element_size != 0) |
size = element_size; |
else |
size = request2size(sizes[i]); |
remainder_size -= size; |
set_size_and_pinuse_of_inuse_chunk(m, p, size); |
p = chunk_plus_offset(p, size); |
} |
else { /* the final element absorbs any overallocation slop */ |
set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size); |
break; |
} |
} |
#if DEBUG |
if (marray != chunks) { |
/* final element must have exactly exhausted chunk */ |
if (element_size != 0) { |
assert(remainder_size == element_size); |
} |
else { |
assert(remainder_size == request2size(sizes[i])); |
} |
check_inuse_chunk(m, mem2chunk(marray)); |
} |
for (i = 0; i != n_elements; ++i) |
check_inuse_chunk(m, mem2chunk(marray[i])); |
#endif /* DEBUG */ |
POSTACTION(m); |
return marray; |
} |
/* -------------------------- public routines ---------------------------- */ |
#if !ONLY_MSPACES |
void* dlmalloc(size_t bytes) { |
/* |
Basic algorithm: |
If a small request (< 256 bytes minus per-chunk overhead): |
1. If one exists, use a remainderless chunk in associated smallbin. |
(Remainderless means that there are too few excess bytes to |
represent as a chunk.) |
2. If it is big enough, use the dv chunk, which is normally the |
chunk adjacent to the one used for the most recent small request. |
3. If one exists, split the smallest available chunk in a bin, |
saving remainder in dv. |
4. If it is big enough, use the top chunk. |
5. If available, get memory from system and use it |
Otherwise, for a large request: |
1. Find the smallest available binned chunk that fits, and use it |
if it is better fitting than dv chunk, splitting if necessary. |
2. If better fitting than any binned chunk, use the dv chunk. |
3. If it is big enough, use the top chunk. |
4. If request size >= mmap threshold, try to directly mmap this chunk. |
5. If available, get memory from system and use it |
The ugly goto's here ensure that postaction occurs along all paths. |
*/ |
if (!PREACTION(gm)) { |
void* mem; |
size_t nb; |
if (bytes <= MAX_SMALL_REQUEST) { |
bindex_t idx; |
binmap_t smallbits; |
nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); |
idx = small_index(nb); |
smallbits = gm->smallmap >> idx; |
if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ |
mchunkptr b, p; |
idx += ~smallbits & 1; /* Uses next bin if idx empty */ |
b = smallbin_at(gm, idx); |
p = b->fd; |
assert(chunksize(p) == small_index2size(idx)); |
unlink_first_small_chunk(gm, b, p, idx); |
set_inuse_and_pinuse(gm, p, small_index2size(idx)); |
mem = chunk2mem(p); |
check_malloced_chunk(gm, mem, nb); |
goto postaction; |
} |
else if (nb > gm->dvsize) { |
if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ |
mchunkptr b, p, r; |
size_t rsize; |
bindex_t i; |
binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); |
binmap_t leastbit = least_bit(leftbits); |
compute_bit2idx(leastbit, i); |
b = smallbin_at(gm, i); |
p = b->fd; |
assert(chunksize(p) == small_index2size(i)); |
unlink_first_small_chunk(gm, b, p, i); |
rsize = small_index2size(i) - nb; |
/* Fit here cannot be remainderless if 4byte sizes */ |
if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) |
set_inuse_and_pinuse(gm, p, small_index2size(i)); |
else { |
set_size_and_pinuse_of_inuse_chunk(gm, p, nb); |
r = chunk_plus_offset(p, nb); |
set_size_and_pinuse_of_free_chunk(r, rsize); |
replace_dv(gm, r, rsize); |
} |
mem = chunk2mem(p); |
check_malloced_chunk(gm, mem, nb); |
goto postaction; |
} |
else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) { |
check_malloced_chunk(gm, mem, nb); |
goto postaction; |
} |
} |
} |
else if (bytes >= MAX_REQUEST) |
nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ |
else { |
nb = pad_request(bytes); |
if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) { |
check_malloced_chunk(gm, mem, nb); |
goto postaction; |
} |
} |
if (nb <= gm->dvsize) { |
size_t rsize = gm->dvsize - nb; |
mchunkptr p = gm->dv; |
if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ |
mchunkptr r = gm->dv = chunk_plus_offset(p, nb); |
gm->dvsize = rsize; |
set_size_and_pinuse_of_free_chunk(r, rsize); |
set_size_and_pinuse_of_inuse_chunk(gm, p, nb); |
} |
else { /* exhaust dv */ |
size_t dvs = gm->dvsize; |
gm->dvsize = 0; |
gm->dv = 0; |
set_inuse_and_pinuse(gm, p, dvs); |
} |
mem = chunk2mem(p); |
check_malloced_chunk(gm, mem, nb); |
goto postaction; |
} |
else if (nb < gm->topsize) { /* Split top */ |
size_t rsize = gm->topsize -= nb; |
mchunkptr p = gm->top; |
mchunkptr r = gm->top = chunk_plus_offset(p, nb); |
r->head = rsize | PINUSE_BIT; |
set_size_and_pinuse_of_inuse_chunk(gm, p, nb); |
mem = chunk2mem(p); |
check_top_chunk(gm, gm->top); |
check_malloced_chunk(gm, mem, nb); |
goto postaction; |
} |
mem = sys_alloc(gm, nb); |
postaction: |
POSTACTION(gm); |
return mem; |
} |
return 0; |
} |
void dlfree(void* mem) { |
/* |
Consolidate freed chunks with preceeding or succeeding bordering |
free chunks, if they exist, and then place in a bin. Intermixed |
with special cases for top, dv, mmapped chunks, and usage errors. |
*/ |
if (mem != 0) { |
mchunkptr p = mem2chunk(mem); |
#if FOOTERS |
mstate fm = get_mstate_for(p); |
if (!ok_magic(fm)) { |
USAGE_ERROR_ACTION(fm, p); |
return; |
} |
#else /* FOOTERS */ |
#define fm gm |
#endif /* FOOTERS */ |
if (!PREACTION(fm)) { |
check_inuse_chunk(fm, p); |
if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) { |
size_t psize = chunksize(p); |
mchunkptr next = chunk_plus_offset(p, psize); |
if (!pinuse(p)) { |
size_t prevsize = p->prev_foot; |
if ((prevsize & IS_MMAPPED_BIT) != 0) { |
prevsize &= ~IS_MMAPPED_BIT; |
psize += prevsize + MMAP_FOOT_PAD; |
if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) |
fm->footprint -= psize; |
goto postaction; |
} |
else { |
mchunkptr prev = chunk_minus_offset(p, prevsize); |
psize += prevsize; |
p = prev; |
if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ |
if (p != fm->dv) { |
unlink_chunk(fm, p, prevsize); |
} |
else if ((next->head & INUSE_BITS) == INUSE_BITS) { |
fm->dvsize = psize; |
set_free_with_pinuse(p, psize, next); |
goto postaction; |
} |
} |
else |
goto erroraction; |
} |
} |
if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) { |
if (!cinuse(next)) { /* consolidate forward */ |
if (next == fm->top) { |
size_t tsize = fm->topsize += psize; |
fm->top = p; |
p->head = tsize | PINUSE_BIT; |
if (p == fm->dv) { |
fm->dv = 0; |
fm->dvsize = 0; |
} |
if (should_trim(fm, tsize)) |
sys_trim(fm, 0); |
goto postaction; |
} |
else if (next == fm->dv) { |
size_t dsize = fm->dvsize += psize; |
fm->dv = p; |
set_size_and_pinuse_of_free_chunk(p, dsize); |
goto postaction; |
} |
else { |
size_t nsize = chunksize(next); |
psize += nsize; |
unlink_chunk(fm, next, nsize); |
set_size_and_pinuse_of_free_chunk(p, psize); |
if (p == fm->dv) { |
fm->dvsize = psize; |
goto postaction; |
} |
} |
} |
else |
set_free_with_pinuse(p, psize, next); |
insert_chunk(fm, p, psize); |
check_free_chunk(fm, p); |
goto postaction; |
} |
} |
erroraction: |
USAGE_ERROR_ACTION(fm, p); |
postaction: |
POSTACTION(fm); |
} |
} |
#if !FOOTERS |
#undef fm |
#endif /* FOOTERS */ |
} |
void* dlcalloc(size_t n_elements, size_t elem_size) { |
void* mem; |
size_t req = 0; |
if (n_elements != 0) { |
req = n_elements * elem_size; |
if (((n_elements | elem_size) & ~(size_t)0xffff) && |
(req / n_elements != elem_size)) |
req = MAX_SIZE_T; /* force downstream failure on overflow */ |
} |
mem = dlmalloc(req); |
if (mem != 0 && calloc_must_clear(mem2chunk(mem))) |
memset(mem, 0, req); |
return mem; |
} |
void* dlrealloc(void* oldmem, size_t bytes) { |
if (oldmem == 0) |
return dlmalloc(bytes); |
#ifdef REALLOC_ZERO_BYTES_FREES |
if (bytes == 0) { |
dlfree(oldmem); |
return 0; |
} |
#endif /* REALLOC_ZERO_BYTES_FREES */ |
else { |
#if ! FOOTERS |
mstate m = gm; |
#else /* FOOTERS */ |
mstate m = get_mstate_for(mem2chunk(oldmem)); |
if (!ok_magic(m)) { |
USAGE_ERROR_ACTION(m, oldmem); |
return 0; |
} |
#endif /* FOOTERS */ |
return internal_realloc(m, oldmem, bytes); |
} |
} |
void* dlmemalign(size_t alignment, size_t bytes) { |
return internal_memalign(gm, alignment, bytes); |
} |
void** dlindependent_calloc(size_t n_elements, size_t elem_size, |
void* chunks[]) { |
size_t sz = elem_size; /* serves as 1-element array */ |
return ialloc(gm, n_elements, &sz, 3, chunks); |
} |
void** dlindependent_comalloc(size_t n_elements, size_t sizes[], |
void* chunks[]) { |
return ialloc(gm, n_elements, sizes, 0, chunks); |
} |
void* dlvalloc(size_t bytes) { |
size_t pagesz; |
init_mparams(); |
pagesz = mparams.page_size; |
return dlmemalign(pagesz, bytes); |
} |
void* dlpvalloc(size_t bytes) { |
size_t pagesz; |
init_mparams(); |
pagesz = mparams.page_size; |
return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE)); |
} |
int dlmalloc_trim(size_t pad) { |
int result = 0; |
if (!PREACTION(gm)) { |
result = sys_trim(gm, pad); |
POSTACTION(gm); |
} |
return result; |
} |
size_t dlmalloc_footprint(void) { |
return gm->footprint; |
} |
size_t dlmalloc_max_footprint(void) { |
return gm->max_footprint; |
} |
#if !NO_MALLINFO |
struct mallinfo dlmallinfo(void) { |
return internal_mallinfo(gm); |
} |
#endif /* NO_MALLINFO */ |
void dlmalloc_stats() { |
internal_malloc_stats(gm); |
} |
size_t dlmalloc_usable_size(void* mem) { |
if (mem != 0) { |
mchunkptr p = mem2chunk(mem); |
if (cinuse(p)) |
return chunksize(p) - overhead_for(p); |
} |
return 0; |
} |
int dlmallopt(int param_number, int value) { |
return change_mparam(param_number, value); |
} |
#endif /* !ONLY_MSPACES */ |
/* ----------------------------- user mspaces ---------------------------- */ |
#if MSPACES |
static mstate init_user_mstate(char* tbase, size_t tsize) { |
size_t msize = pad_request(sizeof(struct malloc_state)); |
mchunkptr mn; |
mchunkptr msp = align_as_chunk(tbase); |
mstate m = (mstate)(chunk2mem(msp)); |
memset(m, 0, msize); |
INITIAL_LOCK(&m->mutex); |
msp->head = (msize|PINUSE_BIT|CINUSE_BIT); |
m->seg.base = m->least_addr = tbase; |
m->seg.size = m->footprint = m->max_footprint = tsize; |
m->magic = mparams.magic; |
m->mflags = mparams.default_mflags; |
disable_contiguous(m); |
init_bins(m); |
mn = next_chunk(mem2chunk(m)); |
init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE); |
check_top_chunk(m, m->top); |
return m; |
} |
mspace create_mspace(size_t capacity, int locked) { |
mstate m = 0; |
size_t msize = pad_request(sizeof(struct malloc_state)); |
init_mparams(); /* Ensure pagesize etc initialized */ |
if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) { |
size_t rs = ((capacity == 0)? mparams.granularity : |
(capacity + TOP_FOOT_SIZE + msize)); |
size_t tsize = granularity_align(rs); |
char* tbase = (char*)(CALL_MMAP(tsize)); |
if (tbase != CMFAIL) { |
m = init_user_mstate(tbase, tsize); |
m->seg.sflags = IS_MMAPPED_BIT; |
set_lock(m, locked); |
} |
} |
return (mspace)m; |
} |
mspace create_mspace_with_base(void* base, size_t capacity, int locked) { |
mstate m = 0; |
size_t msize = pad_request(sizeof(struct malloc_state)); |
init_mparams(); /* Ensure pagesize etc initialized */ |
if (capacity > msize + TOP_FOOT_SIZE && |
capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) { |
m = init_user_mstate((char*)base, capacity); |
m->seg.sflags = EXTERN_BIT; |
set_lock(m, locked); |
} |
return (mspace)m; |
} |
size_t destroy_mspace(mspace msp) { |
size_t freed = 0; |
mstate ms = (mstate)msp; |
if (ok_magic(ms)) { |
msegmentptr sp = &ms->seg; |
while (sp != 0) { |
char* base = sp->base; |
size_t size = sp->size; |
flag_t flag = sp->sflags; |
sp = sp->next; |
if ((flag & IS_MMAPPED_BIT) && !(flag & EXTERN_BIT) && |
CALL_MUNMAP(base, size) == 0) |
freed += size; |
} |
} |
else { |
USAGE_ERROR_ACTION(ms,ms); |
} |
return freed; |
} |
/* |
mspace versions of routines are near-clones of the global |
versions. This is not so nice but better than the alternatives. |
*/ |
void* mspace_malloc(mspace msp, size_t bytes) { |
mstate ms = (mstate)msp; |
if (!ok_magic(ms)) { |
USAGE_ERROR_ACTION(ms,ms); |
return 0; |
} |
if (!PREACTION(ms)) { |
void* mem; |
size_t nb; |
if (bytes <= MAX_SMALL_REQUEST) { |
bindex_t idx; |
binmap_t smallbits; |
nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); |
idx = small_index(nb); |
smallbits = ms->smallmap >> idx; |
if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ |
mchunkptr b, p; |
idx += ~smallbits & 1; /* Uses next bin if idx empty */ |
b = smallbin_at(ms, idx); |
p = b->fd; |
assert(chunksize(p) == small_index2size(idx)); |
unlink_first_small_chunk(ms, b, p, idx); |
set_inuse_and_pinuse(ms, p, small_index2size(idx)); |
mem = chunk2mem(p); |
check_malloced_chunk(ms, mem, nb); |
goto postaction; |
} |
else if (nb > ms->dvsize) { |
if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ |
mchunkptr b, p, r; |
size_t rsize; |
bindex_t i; |
binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); |
binmap_t leastbit = least_bit(leftbits); |
compute_bit2idx(leastbit, i); |
b = smallbin_at(ms, i); |
p = b->fd; |
assert(chunksize(p) == small_index2size(i)); |
unlink_first_small_chunk(ms, b, p, i); |
rsize = small_index2size(i) - nb; |
/* Fit here cannot be remainderless if 4byte sizes */ |
if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) |
set_inuse_and_pinuse(ms, p, small_index2size(i)); |
else { |
set_size_and_pinuse_of_inuse_chunk(ms, p, nb); |
r = chunk_plus_offset(p, nb); |
set_size_and_pinuse_of_free_chunk(r, rsize); |
replace_dv(ms, r, rsize); |
} |
mem = chunk2mem(p); |
check_malloced_chunk(ms, mem, nb); |
goto postaction; |
} |
else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) { |
check_malloced_chunk(ms, mem, nb); |
goto postaction; |
} |
} |
} |
else if (bytes >= MAX_REQUEST) |
nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ |
else { |
nb = pad_request(bytes); |
if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) { |
check_malloced_chunk(ms, mem, nb); |
goto postaction; |
} |
} |
if (nb <= ms->dvsize) { |
size_t rsize = ms->dvsize - nb; |
mchunkptr p = ms->dv; |
if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ |
mchunkptr r = ms->dv = chunk_plus_offset(p, nb); |
ms->dvsize = rsize; |
set_size_and_pinuse_of_free_chunk(r, rsize); |
set_size_and_pinuse_of_inuse_chunk(ms, p, nb); |
} |
else { /* exhaust dv */ |
size_t dvs = ms->dvsize; |
ms->dvsize = 0; |
ms->dv = 0; |
set_inuse_and_pinuse(ms, p, dvs); |
} |
mem = chunk2mem(p); |
check_malloced_chunk(ms, mem, nb); |
goto postaction; |
} |
else if (nb < ms->topsize) { /* Split top */ |
size_t rsize = ms->topsize -= nb; |
mchunkptr p = ms->top; |
mchunkptr r = ms->top = chunk_plus_offset(p, nb); |
r->head = rsize | PINUSE_BIT; |
set_size_and_pinuse_of_inuse_chunk(ms, p, nb); |
mem = chunk2mem(p); |
check_top_chunk(ms, ms->top); |
check_malloced_chunk(ms, mem, nb); |
goto postaction; |
} |
mem = sys_alloc(ms, nb); |
postaction: |
POSTACTION(ms); |
return mem; |
} |
return 0; |
} |
void mspace_free(mspace msp, void* mem) { |
if (mem != 0) { |
mchunkptr p = mem2chunk(mem); |
#if FOOTERS |
mstate fm = get_mstate_for(p); |
#else /* FOOTERS */ |
mstate fm = (mstate)msp; |
#endif /* FOOTERS */ |
if (!ok_magic(fm)) { |
USAGE_ERROR_ACTION(fm, p); |
return; |
} |
if (!PREACTION(fm)) { |
check_inuse_chunk(fm, p); |
if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) { |
size_t psize = chunksize(p); |
mchunkptr next = chunk_plus_offset(p, psize); |
if (!pinuse(p)) { |
size_t prevsize = p->prev_foot; |
if ((prevsize & IS_MMAPPED_BIT) != 0) { |
prevsize &= ~IS_MMAPPED_BIT; |
psize += prevsize + MMAP_FOOT_PAD; |
if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) |
fm->footprint -= psize; |
goto postaction; |
} |
else { |
mchunkptr prev = chunk_minus_offset(p, prevsize); |
psize += prevsize; |
p = prev; |
if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ |
if (p != fm->dv) { |
unlink_chunk(fm, p, prevsize); |
} |
else if ((next->head & INUSE_BITS) == INUSE_BITS) { |
fm->dvsize = psize; |
set_free_with_pinuse(p, psize, next); |
goto postaction; |
} |
} |
else |
goto erroraction; |
} |
} |
if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) { |
if (!cinuse(next)) { /* consolidate forward */ |
if (next == fm->top) { |
size_t tsize = fm->topsize += psize; |
fm->top = p; |
p->head = tsize | PINUSE_BIT; |
if (p == fm->dv) { |
fm->dv = 0; |
fm->dvsize = 0; |
} |
if (should_trim(fm, tsize)) |
sys_trim(fm, 0); |
goto postaction; |
} |
else if (next == fm->dv) { |
size_t dsize = fm->dvsize += psize; |
fm->dv = p; |
set_size_and_pinuse_of_free_chunk(p, dsize); |
goto postaction; |
} |
else { |
size_t nsize = chunksize(next); |
psize += nsize; |
unlink_chunk(fm, next, nsize); |
set_size_and_pinuse_of_free_chunk(p, psize); |
if (p == fm->dv) { |
fm->dvsize = psize; |
goto postaction; |
} |
} |
} |
else |
set_free_with_pinuse(p, psize, next); |
insert_chunk(fm, p, psize); |
check_free_chunk(fm, p); |
goto postaction; |
} |
} |
erroraction: |
USAGE_ERROR_ACTION(fm, p); |
postaction: |
POSTACTION(fm); |
} |
} |
} |
void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) { |
void* mem; |
size_t req = 0; |
mstate ms = (mstate)msp; |
if (!ok_magic(ms)) { |
USAGE_ERROR_ACTION(ms,ms); |
return 0; |
} |
if (n_elements != 0) { |
req = n_elements * elem_size; |
if (((n_elements | elem_size) & ~(size_t)0xffff) && |
(req / n_elements != elem_size)) |
req = MAX_SIZE_T; /* force downstream failure on overflow */ |
} |
mem = internal_malloc(ms, req); |
if (mem != 0 && calloc_must_clear(mem2chunk(mem))) |
memset(mem, 0, req); |
return mem; |
} |
void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) { |
if (oldmem == 0) |
return mspace_malloc(msp, bytes); |
#ifdef REALLOC_ZERO_BYTES_FREES |
if (bytes == 0) { |
mspace_free(msp, oldmem); |
return 0; |
} |
#endif /* REALLOC_ZERO_BYTES_FREES */ |
else { |
#if FOOTERS |
mchunkptr p = mem2chunk(oldmem); |
mstate ms = get_mstate_for(p); |
#else /* FOOTERS */ |
mstate ms = (mstate)msp; |
#endif /* FOOTERS */ |
if (!ok_magic(ms)) { |
USAGE_ERROR_ACTION(ms,ms); |
return 0; |
} |
return internal_realloc(ms, oldmem, bytes); |
} |
} |
void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) { |
mstate ms = (mstate)msp; |
if (!ok_magic(ms)) { |
USAGE_ERROR_ACTION(ms,ms); |
return 0; |
} |
return internal_memalign(ms, alignment, bytes); |
} |
void** mspace_independent_calloc(mspace msp, size_t n_elements, |
size_t elem_size, void* chunks[]) { |
size_t sz = elem_size; /* serves as 1-element array */ |
mstate ms = (mstate)msp; |
if (!ok_magic(ms)) { |
USAGE_ERROR_ACTION(ms,ms); |
return 0; |
} |
return ialloc(ms, n_elements, &sz, 3, chunks); |
} |
void** mspace_independent_comalloc(mspace msp, size_t n_elements, |
size_t sizes[], void* chunks[]) { |
mstate ms = (mstate)msp; |
if (!ok_magic(ms)) { |
USAGE_ERROR_ACTION(ms,ms); |
return 0; |
} |
return ialloc(ms, n_elements, sizes, 0, chunks); |
} |
int mspace_trim(mspace msp, size_t pad) { |
int result = 0; |
mstate ms = (mstate)msp; |
if (ok_magic(ms)) { |
if (!PREACTION(ms)) { |
result = sys_trim(ms, pad); |
POSTACTION(ms); |
} |
} |
else { |
USAGE_ERROR_ACTION(ms,ms); |
} |
return result; |
} |
void mspace_malloc_stats(mspace msp) { |
mstate ms = (mstate)msp; |
if (ok_magic(ms)) { |
internal_malloc_stats(ms); |
} |
else { |
USAGE_ERROR_ACTION(ms,ms); |
} |
} |
size_t mspace_footprint(mspace msp) { |
size_t result; |
mstate ms = (mstate)msp; |
if (ok_magic(ms)) { |
result = ms->footprint; |
} |
USAGE_ERROR_ACTION(ms,ms); |
return result; |
} |
size_t mspace_max_footprint(mspace msp) { |
size_t result; |
mstate ms = (mstate)msp; |
if (ok_magic(ms)) { |
result = ms->max_footprint; |
} |
USAGE_ERROR_ACTION(ms,ms); |
return result; |
} |
#if !NO_MALLINFO |
struct mallinfo mspace_mallinfo(mspace msp) { |
mstate ms = (mstate)msp; |
if (!ok_magic(ms)) { |
USAGE_ERROR_ACTION(ms,ms); |
} |
return internal_mallinfo(ms); |
} |
#endif /* NO_MALLINFO */ |
int mspace_mallopt(int param_number, int value) { |
return change_mparam(param_number, value); |
} |
#endif /* MSPACES */ |
/* -------------------- Alternative MORECORE functions ------------------- */ |
/* |
Guidelines for creating a custom version of MORECORE: |
* For best performance, MORECORE should allocate in multiples of pagesize. |
* MORECORE may allocate more memory than requested. (Or even less, |
but this will usually result in a malloc failure.) |
* MORECORE must not allocate memory when given argument zero, but |
instead return one past the end address of memory from previous |
nonzero call. |
* For best performance, consecutive calls to MORECORE with positive |
arguments should return increasing addresses, indicating that |
space has been contiguously extended. |
* Even though consecutive calls to MORECORE need not return contiguous |
addresses, it must be OK for malloc'ed chunks to span multiple |
regions in those cases where they do happen to be contiguous. |
* MORECORE need not handle negative arguments -- it may instead |
just return MFAIL when given negative arguments. |
Negative arguments are always multiples of pagesize. MORECORE |
must not misinterpret negative args as large positive unsigned |
args. You can suppress all such calls from even occurring by defining |
MORECORE_CANNOT_TRIM, |
As an example alternative MORECORE, here is a custom allocator |
kindly contributed for pre-OSX macOS. It uses virtually but not |
necessarily physically contiguous non-paged memory (locked in, |
present and won't get swapped out). You can use it by uncommenting |
this section, adding some #includes, and setting up the appropriate |
defines above: |
#define MORECORE osMoreCore |
There is also a shutdown routine that should somehow be called for |
cleanup upon program exit. |
#define MAX_POOL_ENTRIES 100 |
#define MINIMUM_MORECORE_SIZE (64 * 1024U) |
static int next_os_pool; |
void *our_os_pools[MAX_POOL_ENTRIES]; |
void *osMoreCore(int size) |
{ |
void *ptr = 0; |
static void *sbrk_top = 0; |
if (size > 0) |
{ |
if (size < MINIMUM_MORECORE_SIZE) |
size = MINIMUM_MORECORE_SIZE; |
if (CurrentExecutionLevel() == kTaskLevel) |
ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0); |
if (ptr == 0) |
{ |
return (void *) MFAIL; |
} |
// save ptrs so they can be freed during cleanup |
our_os_pools[next_os_pool] = ptr; |
next_os_pool++; |
ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK); |
sbrk_top = (char *) ptr + size; |
return ptr; |
} |
else if (size < 0) |
{ |
// we don't currently support shrink behavior |
return (void *) MFAIL; |
} |
else |
{ |
return sbrk_top; |
} |
} |
// cleanup any allocated memory pools |
// called as last thing before shutting down driver |
void osCleanupMem(void) |
{ |
void **ptr; |
for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++) |
if (*ptr) |
{ |
PoolDeallocate(*ptr); |
*ptr = 0; |
} |
} |
*/ |
/* ----------------------------------------------------------------------- |
History: |
V2.8.3 Thu Sep 22 11:16:32 2005 Doug Lea (dl at gee) |
* Add max_footprint functions |
* Ensure all appropriate literals are size_t |
* Fix conditional compilation problem for some #define settings |
* Avoid concatenating segments with the one provided |
in create_mspace_with_base |
* Rename some variables to avoid compiler shadowing warnings |
* Use explicit lock initialization. |
* Better handling of sbrk interference. |
* Simplify and fix segment insertion, trimming and mspace_destroy |
* Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x |
* Thanks especially to Dennis Flanagan for help on these. |
V2.8.2 Sun Jun 12 16:01:10 2005 Doug Lea (dl at gee) |
* Fix memalign brace error. |
V2.8.1 Wed Jun 8 16:11:46 2005 Doug Lea (dl at gee) |
* Fix improper #endif nesting in C++ |
* Add explicit casts needed for C++ |
V2.8.0 Mon May 30 14:09:02 2005 Doug Lea (dl at gee) |
* Use trees for large bins |
* Support mspaces |
* Use segments to unify sbrk-based and mmap-based system allocation, |
removing need for emulation on most platforms without sbrk. |
* Default safety checks |
* Optional footer checks. Thanks to William Robertson for the idea. |
* Internal code refactoring |
* Incorporate suggestions and platform-specific changes. |
Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas, |
Aaron Bachmann, Emery Berger, and others. |
* Speed up non-fastbin processing enough to remove fastbins. |
* Remove useless cfree() to avoid conflicts with other apps. |
* Remove internal memcpy, memset. Compilers handle builtins better. |
* Remove some options that no one ever used and rename others. |
V2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee) |
* Fix malloc_state bitmap array misdeclaration |
V2.7.1 Thu Jul 25 10:58:03 2002 Doug Lea (dl at gee) |
* Allow tuning of FIRST_SORTED_BIN_SIZE |
* Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte. |
* Better detection and support for non-contiguousness of MORECORE. |
Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger |
* Bypass most of malloc if no frees. Thanks To Emery Berger. |
* Fix freeing of old top non-contiguous chunk im sysmalloc. |
* Raised default trim and map thresholds to 256K. |
* Fix mmap-related #defines. Thanks to Lubos Lunak. |
* Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield. |
* Branch-free bin calculation |
* Default trim and mmap thresholds now 256K. |
V2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee) |
* Introduce independent_comalloc and independent_calloc. |
Thanks to Michael Pachos for motivation and help. |
* Make optional .h file available |
* Allow > 2GB requests on 32bit systems. |
* new WIN32 sbrk, mmap, munmap, lock code from <Walter@GeNeSys-e.de>. |
Thanks also to Andreas Mueller <a.mueller at paradatec.de>, |
and Anonymous. |
* Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for |
helping test this.) |
* memalign: check alignment arg |
* realloc: don't try to shift chunks backwards, since this |
leads to more fragmentation in some programs and doesn't |
seem to help in any others. |
* Collect all cases in malloc requiring system memory into sysmalloc |
* Use mmap as backup to sbrk |
* Place all internal state in malloc_state |
* Introduce fastbins (although similar to 2.5.1) |
* Many minor tunings and cosmetic improvements |
* Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK |
* Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS |
Thanks to Tony E. Bennett <tbennett@nvidia.com> and others. |
* Include errno.h to support default failure action. |
V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee) |
* return null for negative arguments |
* Added Several WIN32 cleanups from Martin C. Fong <mcfong at yahoo.com> |
* Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h' |
(e.g. WIN32 platforms) |
* Cleanup header file inclusion for WIN32 platforms |
* Cleanup code to avoid Microsoft Visual C++ compiler complaints |
* Add 'USE_DL_PREFIX' to quickly allow co-existence with existing |
memory allocation routines |
* Set 'malloc_getpagesize' for WIN32 platforms (needs more work) |
* Use 'assert' rather than 'ASSERT' in WIN32 code to conform to |
usage of 'assert' in non-WIN32 code |
* Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to |
avoid infinite loop |
* Always call 'fREe()' rather than 'free()' |
V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee) |
* Fixed ordering problem with boundary-stamping |
V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee) |
* Added pvalloc, as recommended by H.J. Liu |
* Added 64bit pointer support mainly from Wolfram Gloger |
* Added anonymously donated WIN32 sbrk emulation |
* Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen |
* malloc_extend_top: fix mask error that caused wastage after |
foreign sbrks |
* Add linux mremap support code from HJ Liu |
V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee) |
* Integrated most documentation with the code. |
* Add support for mmap, with help from |
Wolfram Gloger (Gloger@lrz.uni-muenchen.de). |
* Use last_remainder in more cases. |
* Pack bins using idea from colin@nyx10.cs.du.edu |
* Use ordered bins instead of best-fit threshhold |
* Eliminate block-local decls to simplify tracing and debugging. |
* Support another case of realloc via move into top |
* Fix error occuring when initial sbrk_base not word-aligned. |
* Rely on page size for units instead of SBRK_UNIT to |
avoid surprises about sbrk alignment conventions. |
* Add mallinfo, mallopt. Thanks to Raymond Nijssen |
(raymond@es.ele.tue.nl) for the suggestion. |
* Add `pad' argument to malloc_trim and top_pad mallopt parameter. |
* More precautions for cases where other routines call sbrk, |
courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de). |
* Added macros etc., allowing use in linux libc from |
H.J. Lu (hjl@gnu.ai.mit.edu) |
* Inverted this history list |
V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee) |
* Re-tuned and fixed to behave more nicely with V2.6.0 changes. |
* Removed all preallocation code since under current scheme |
the work required to undo bad preallocations exceeds |
the work saved in good cases for most test programs. |
* No longer use return list or unconsolidated bins since |
no scheme using them consistently outperforms those that don't |
given above changes. |
* Use best fit for very large chunks to prevent some worst-cases. |
* Added some support for debugging |
V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee) |
* Removed footers when chunks are in use. Thanks to |
Paul Wilson (wilson@cs.texas.edu) for the suggestion. |
V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee) |
* Added malloc_trim, with help from Wolfram Gloger |
(wmglo@Dent.MED.Uni-Muenchen.DE). |
V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g) |
V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g) |
* realloc: try to expand in both directions |
* malloc: swap order of clean-bin strategy; |
* realloc: only conditionally expand backwards |
* Try not to scavenge used bins |
* Use bin counts as a guide to preallocation |
* Occasionally bin return list chunks in first scan |
* Add a few optimizations from colin@nyx10.cs.du.edu |
V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g) |
* faster bin computation & slightly different binning |
* merged all consolidations to one part of malloc proper |
(eliminating old malloc_find_space & malloc_clean_bin) |
* Scan 2 returns chunks (not just 1) |
* Propagate failure in realloc if malloc returns 0 |
* Add stuff to allow compilation on non-ANSI compilers |
from kpv@research.att.com |
V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu) |
* removed potential for odd address access in prev_chunk |
* removed dependency on getpagesize.h |
* misc cosmetics and a bit more internal documentation |
* anticosmetics: mangled names in macros to evade debugger strangeness |
* tested on sparc, hp-700, dec-mips, rs6000 |
with gcc & native cc (hp, dec only) allowing |
Detlefs & Zorn comparison study (in SIGPLAN Notices.) |
Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu) |
* Based loosely on libg++-1.2X malloc. (It retains some of the overall |
structure of old version, but most details differ.) |
*/ |
/** @} |
*/ |
/branches/dd/uspace/lib/softfloat/Makefile |
---|
36,7 → 36,7 |
include $(LIBC_PREFIX)/Makefile.toolchain |
CFLAGS += -Iinclude -Iarch/$(UARCH)/include/ |
CFLAGS +=-Iinclude -Iarch/$(UARCH)/include/ |
## Sources |
# |
/branches/dd/uspace/lib/softfloat/include/sftypes.h |
---|
26,7 → 26,7 |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup softfloat |
/** @addtogroup softfloat |
* @{ |
*/ |
/** @file |
41,40 → 41,40 |
typedef union { |
float f; |
uint32_t binary; |
struct { |
#if defined(__BE__) |
uint32_t sign : 1; |
uint32_t exp : 8; |
uint32_t fraction : 23; |
#elif defined(__LE__) |
uint32_t fraction : 23; |
uint32_t exp : 8; |
uint32_t sign : 1; |
#else |
#error Unknown endianess |
struct { |
#if defined(ARCH_IS_BIG_ENDIAN) |
uint32_t sign:1; |
uint32_t exp:8; |
uint32_t fraction:23; |
#elif defined(ARCH_IS_LITTLE_ENDIAN) |
uint32_t fraction:23; |
uint32_t exp:8; |
uint32_t sign:1; |
#else |
#error "Unknown endians." |
#endif |
} parts __attribute__ ((packed)); |
} float32; |
} float32; |
typedef union { |
double d; |
uint64_t binary; |
struct { |
#if defined(__BE__) |
uint64_t sign : 1; |
uint64_t exp : 11; |
uint64_t fraction : 52; |
#elif defined(__LE__) |
uint64_t fraction : 52; |
uint64_t exp : 11; |
uint64_t sign : 1; |
#else |
#error Unknown endianess |
struct { |
#if defined(ARCH_IS_BIG_ENDIAN) |
uint64_t sign:1; |
uint64_t exp:11; |
uint64_t fraction:52; |
#elif defined(ARCH_IS_LITTLE_ENDIAN) |
uint64_t fraction:52; |
uint64_t exp:11; |
uint64_t sign:1; |
#else |
#error "Unknown endians." |
#endif |
} parts __attribute__ ((packed)); |
} float64; |
} parts __attribute__ ((packed)); |
} float64; |
#define FLOAT32_MAX 0x7f800000 |
#define FLOAT32_MIN 0xff800000 |
109,5 → 109,7 |
#endif |
/** @} |
/** @} |
*/ |
/branches/dd/kernel/genarch/src/mm/page_ht.c |
---|
192,8 → 192,6 |
t->k = !(flags & PAGE_USER); |
t->c = (flags & PAGE_CACHEABLE) != 0; |
t->p = !(flags & PAGE_NOT_PRESENT); |
t->a = false; |
t->d = false; |
t->as = as; |
t->page = ALIGN_DOWN(page, PAGE_SIZE); |
/branches/dd/kernel/genarch/src/acpi/acpi.c |
---|
167,13 → 167,10 |
LOG("%p: ACPI Root System Description Pointer\n", acpi_rsdp); |
acpi_rsdt = (struct acpi_rsdt *) (unative_t) acpi_rsdp->rsdt_address; |
if (acpi_rsdp->revision) |
acpi_xsdt = (struct acpi_xsdt *) ((uintptr_t) acpi_rsdp->xsdt_address); |
if (acpi_rsdp->revision) acpi_xsdt = (struct acpi_xsdt *) ((uintptr_t) acpi_rsdp->xsdt_address); |
if (acpi_rsdt) |
map_sdt((struct acpi_sdt_header *) acpi_rsdt); |
if (acpi_xsdt) |
map_sdt((struct acpi_sdt_header *) acpi_xsdt); |
if (acpi_rsdt) map_sdt((struct acpi_sdt_header *) acpi_rsdt); |
if (acpi_xsdt) map_sdt((struct acpi_sdt_header *) acpi_xsdt); |
if (acpi_rsdt && !acpi_sdt_check((uint8_t *) acpi_rsdt)) { |
printf("RSDT: bad checksum\n"); |
184,10 → 181,8 |
return; |
} |
if (acpi_xsdt) |
configure_via_xsdt(); |
else if (acpi_rsdt) |
configure_via_rsdt(); |
if (acpi_xsdt) configure_via_xsdt(); |
else if (acpi_rsdt) configure_via_rsdt(); |
} |
/branches/dd/kernel/genarch/src/kbrd/scanc_mac.c |
---|
File deleted |
/branches/dd/kernel/genarch/src/kbrd/kbrd.c |
---|
45,10 → 45,6 |
#include <genarch/kbrd/scanc_sun.h> |
#endif |
#ifdef CONFIG_MAC_KBD |
#include <genarch/kbrd/scanc_mac.h> |
#endif |
#include <synch/spinlock.h> |
#include <console/chardev.h> |
#include <console/console.h> |
/branches/dd/kernel/genarch/src/drivers/via-cuda/cuda.c |
---|
1,6 → 1,5 |
/* |
* Copyright (c) 2006 Martin Decky |
* Copyright (c) 2009 Jiri Svoboda |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
39,53 → 38,16 |
#include <arch/asm.h> |
#include <mm/slab.h> |
#include <ddi/device.h> |
#include <synch/spinlock.h> |
static irq_ownership_t cuda_claim(irq_t *irq); |
static void cuda_irq_handler(irq_t *irq); |
static irq_ownership_t cuda_claim(irq_t *irq) |
{ |
return IRQ_DECLINE; |
} |
static void cuda_irq_listen(irq_t *irq); |
static void cuda_irq_receive(irq_t *irq); |
static void cuda_irq_rcv_end(irq_t *irq, void *buf, size_t *len); |
static void cuda_irq_send_start(irq_t *irq); |
static void cuda_irq_send(irq_t *irq); |
static void cuda_irq_handler(irq_t *irq) |
{ |
} |
static void cuda_packet_handle(cuda_instance_t *instance, uint8_t *buf, size_t len); |
static void cuda_send_start(cuda_instance_t *instance); |
static void cuda_autopoll_set(cuda_instance_t *instance, bool enable); |
/** B register fields */ |
enum { |
TREQ = 0x08, |
TACK = 0x10, |
TIP = 0x20 |
}; |
/** IER register fields */ |
enum { |
IER_CLR = 0x00, |
IER_SET = 0x80, |
SR_INT = 0x04, |
ALL_INT = 0x7f |
}; |
/** ACR register fields */ |
enum { |
SR_OUT = 0x10 |
}; |
/** Packet types */ |
enum { |
PT_ADB = 0x00, |
PT_CUDA = 0x01 |
}; |
/** CUDA packet types */ |
enum { |
CPT_AUTOPOLL = 0x01 |
}; |
cuda_instance_t *cuda_init(cuda_t *dev, inr_t inr, cir_t cir, void *cir_arg) |
{ |
cuda_instance_t *instance |
93,15 → 55,7 |
if (instance) { |
instance->cuda = dev; |
instance->kbrdin = NULL; |
instance->xstate = cx_listen; |
instance->bidx = 0; |
instance->snd_bytes = 0; |
spinlock_initialize(&instance->dev_lock, "cuda_dev"); |
/* Disable all interrupts from CUDA. */ |
pio_write_8(&dev->ier, IER_CLR | ALL_INT); |
irq_initialize(&instance->irq); |
instance->irq.devno = device_assign_devno(); |
instance->irq.inr = inr; |
110,251 → 64,15 |
instance->irq.instance = instance; |
instance->irq.cir = cir; |
instance->irq.cir_arg = cir_arg; |
instance->irq.preack = true; |
} |
return instance; |
} |
#include <print.h> |
void cuda_wire(cuda_instance_t *instance, indev_t *kbrdin) |
{ |
cuda_t *dev = instance->cuda; |
ASSERT(instance); |
ASSERT(kbrdin); |
instance->kbrdin = kbrdin; |
irq_register(&instance->irq); |
/* Enable SR interrupt. */ |
pio_write_8(&dev->ier, TIP | TREQ); |
pio_write_8(&dev->ier, IER_SET | SR_INT); |
/* Enable ADB autopolling. */ |
cuda_autopoll_set(instance, true); |
} |
static irq_ownership_t cuda_claim(irq_t *irq) |
{ |
cuda_instance_t *instance = irq->instance; |
cuda_t *dev = instance->cuda; |
uint8_t ifr; |
spinlock_lock(&instance->dev_lock); |
ifr = pio_read_8(&dev->ifr); |
spinlock_unlock(&instance->dev_lock); |
if ((ifr & SR_INT) == 0) |
return IRQ_DECLINE; |
return IRQ_ACCEPT; |
} |
static void cuda_irq_handler(irq_t *irq) |
{ |
cuda_instance_t *instance = irq->instance; |
uint8_t rbuf[CUDA_RCV_BUF_SIZE]; |
size_t len; |
bool handle; |
handle = false; |
len = 0; |
spinlock_lock(&instance->dev_lock); |
/* Lower IFR.SR_INT so that CUDA can generate next int by raising it. */ |
pio_write_8(&instance->cuda->ifr, SR_INT); |
switch (instance->xstate) { |
case cx_listen: cuda_irq_listen(irq); break; |
case cx_receive: cuda_irq_receive(irq); break; |
case cx_rcv_end: cuda_irq_rcv_end(irq, rbuf, &len); |
handle = true; break; |
case cx_send_start: cuda_irq_send_start(irq); break; |
case cx_send: cuda_irq_send(irq); break; |
} |
spinlock_unlock(&instance->dev_lock); |
/* Handle an incoming packet. */ |
if (handle) |
cuda_packet_handle(instance, rbuf, len); |
} |
/** Interrupt in listen state. |
* |
* Start packet reception. |
*/ |
static void cuda_irq_listen(irq_t *irq) |
{ |
cuda_instance_t *instance = irq->instance; |
cuda_t *dev = instance->cuda; |
uint8_t b; |
b = pio_read_8(&dev->b); |
if ((b & TREQ) != 0) { |
printf("cuda_irq_listen: no TREQ?!\n"); |
return; |
} |
pio_read_8(&dev->sr); |
pio_write_8(&dev->b, pio_read_8(&dev->b) & ~TIP); |
instance->xstate = cx_receive; |
} |
/** Interrupt in receive state. |
* |
* Receive next byte of packet. |
*/ |
static void cuda_irq_receive(irq_t *irq) |
{ |
cuda_instance_t *instance = irq->instance; |
cuda_t *dev = instance->cuda; |
uint8_t b, data; |
data = pio_read_8(&dev->sr); |
if (instance->bidx < CUDA_RCV_BUF_SIZE) |
instance->rcv_buf[instance->bidx++] = data; |
b = pio_read_8(&dev->b); |
if ((b & TREQ) == 0) { |
pio_write_8(&dev->b, b ^ TACK); |
} else { |
pio_write_8(&dev->b, b | TACK | TIP); |
instance->xstate = cx_rcv_end; |
} |
} |
/** Interrupt in rcv_end state. |
* |
* Terminate packet reception. Either go back to listen state or start |
* receiving another packet if CUDA has one for us. |
*/ |
static void cuda_irq_rcv_end(irq_t *irq, void *buf, size_t *len) |
{ |
cuda_instance_t *instance = irq->instance; |
cuda_t *dev = instance->cuda; |
uint8_t data, b; |
b = pio_read_8(&dev->b); |
data = pio_read_8(&dev->sr); |
if ((b & TREQ) == 0) { |
instance->xstate = cx_receive; |
pio_write_8(&dev->b, b & ~TIP); |
} else { |
instance->xstate = cx_listen; |
cuda_send_start(instance); |
} |
memcpy(buf, instance->rcv_buf, instance->bidx); |
*len = instance->bidx; |
instance->bidx = 0; |
} |
/** Interrupt in send_start state. |
* |
* Process result of sending first byte (and send second on success). |
*/ |
static void cuda_irq_send_start(irq_t *irq) |
{ |
cuda_instance_t *instance = irq->instance; |
cuda_t *dev = instance->cuda; |
uint8_t b; |
b = pio_read_8(&dev->b); |
if ((b & TREQ) == 0) { |
/* Collision */ |
pio_write_8(&dev->acr, pio_read_8(&dev->acr) & ~SR_OUT); |
pio_read_8(&dev->sr); |
pio_write_8(&dev->b, pio_read_8(&dev->b) | TIP | TACK); |
instance->xstate = cx_listen; |
return; |
} |
pio_write_8(&dev->sr, instance->snd_buf[1]); |
pio_write_8(&dev->b, pio_read_8(&dev->b) ^ TACK); |
instance->bidx = 2; |
instance->xstate = cx_send; |
} |
/** Interrupt in send state. |
* |
* Send next byte or terminate transmission. |
*/ |
static void cuda_irq_send(irq_t *irq) |
{ |
cuda_instance_t *instance = irq->instance; |
cuda_t *dev = instance->cuda; |
if (instance->bidx < instance->snd_bytes) { |
/* Send next byte. */ |
pio_write_8(&dev->sr, instance->snd_buf[instance->bidx++]); |
pio_write_8(&dev->b, pio_read_8(&dev->b) ^ TACK); |
return; |
} |
/* End transfer. */ |
instance->snd_bytes = 0; |
instance->bidx = 0; |
pio_write_8(&dev->acr, pio_read_8(&dev->acr) & ~SR_OUT); |
pio_read_8(&dev->sr); |
pio_write_8(&dev->b, pio_read_8(&dev->b) | TACK | TIP); |
instance->xstate = cx_listen; |
/* TODO: Match reply with request. */ |
} |
static void cuda_packet_handle(cuda_instance_t *instance, uint8_t *data, size_t len) |
{ |
if (data[0] != 0x00 || data[1] != 0x40 || (data[2] != 0x2c |
&& data[2] != 0x8c)) |
return; |
/* The packet contains one or two scancodes. */ |
if (data[3] != 0xff) |
indev_push_character(instance->kbrdin, data[3]); |
if (data[4] != 0xff) |
indev_push_character(instance->kbrdin, data[4]); |
} |
static void cuda_autopoll_set(cuda_instance_t *instance, bool enable) |
{ |
instance->snd_buf[0] = PT_CUDA; |
instance->snd_buf[1] = CPT_AUTOPOLL; |
instance->snd_buf[2] = enable ? 0x01 : 0x00; |
instance->snd_bytes = 3; |
instance->bidx = 0; |
cuda_send_start(instance); |
} |
static void cuda_send_start(cuda_instance_t *instance) |
{ |
cuda_t *dev = instance->cuda; |
ASSERT(instance->xstate == cx_listen); |
if (instance->snd_bytes == 0) |
return; |
/* Check for incoming data. */ |
if ((pio_read_8(&dev->b) & TREQ) == 0) |
return; |
pio_write_8(&dev->acr, pio_read_8(&dev->acr) | SR_OUT); |
pio_write_8(&dev->sr, instance->snd_buf[0]); |
pio_write_8(&dev->b, pio_read_8(&dev->b) & ~TIP); |
instance->xstate = cx_send_start; |
} |
/** @} |
*/ |
/branches/dd/kernel/genarch/include/kbrd/scanc_mac.h |
---|
File deleted |
/branches/dd/kernel/genarch/include/drivers/via-cuda/cuda.h |
---|
38,80 → 38,14 |
#include <ddi/irq.h> |
#include <arch/types.h> |
#include <console/chardev.h> |
#include <synch/spinlock.h> |
typedef struct { |
uint8_t b; |
uint8_t pad0[0x1ff]; |
uint8_t a; |
uint8_t pad1[0x1ff]; |
uint8_t dirb; |
uint8_t pad2[0x1ff]; |
uint8_t dira; |
uint8_t pad3[0x1ff]; |
uint8_t t1cl; |
uint8_t pad4[0x1ff]; |
uint8_t t1ch; |
uint8_t pad5[0x1ff]; |
uint8_t t1ll; |
uint8_t pad6[0x1ff]; |
uint8_t t1lh; |
uint8_t pad7[0x1ff]; |
uint8_t t2cl; |
uint8_t pad8[0x1ff]; |
uint8_t t2ch; |
uint8_t pad9[0x1ff]; |
uint8_t sr; |
uint8_t pad10[0x1ff]; |
uint8_t acr; |
uint8_t pad11[0x1ff]; |
uint8_t pcr; |
uint8_t pad12[0x1ff]; |
uint8_t ifr; |
uint8_t pad13[0x1ff]; |
uint8_t ier; |
uint8_t pad14[0x1ff]; |
uint8_t anh; |
uint8_t pad15[0x1ff]; |
} cuda_t; |
enum { |
CUDA_RCV_BUF_SIZE = 5 |
}; |
enum cuda_xfer_state { |
cx_listen, |
cx_receive, |
cx_rcv_end, |
cx_send_start, |
cx_send |
}; |
typedef struct { |
irq_t irq; |
cuda_t *cuda; |
indev_t *kbrdin; |
uint8_t rcv_buf[CUDA_RCV_BUF_SIZE]; |
uint8_t snd_buf[CUDA_RCV_BUF_SIZE]; |
size_t bidx; |
size_t snd_bytes; |
enum cuda_xfer_state xstate; |
SPINLOCK_DECLARE(dev_lock); |
} cuda_instance_t; |
extern cuda_instance_t *cuda_init(cuda_t *, inr_t, cir_t, void *); |
/branches/dd/kernel/genarch/Makefile.inc |
---|
110,12 → 110,6 |
genarch/src/kbrd/scanc_sun.c |
endif |
ifeq ($(CONFIG_MAC_KBD),y) |
GENARCH_SOURCES += \ |
genarch/src/kbrd/kbrd.c \ |
genarch/src/kbrd/scanc_mac.c |
endif |
ifeq ($(CONFIG_SRLN),y) |
GENARCH_SOURCES += \ |
genarch/src/srln/srln.c |
/branches/dd/kernel/generic/include/string.h |
---|
57,6 → 57,8 |
#define U_CURSOR 0x2588 |
#define U_BOM 0xfeff |
/**< No size limit constant */ |
#define STR_NO_LIMIT ((size_t) -1) |
/branches/dd/kernel/generic/include/byteorder.h |
---|
26,7 → 26,7 |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup generic |
/** @addtogroup generic |
* @{ |
*/ |
/** @file |
35,47 → 35,48 |
#ifndef KERN_BYTEORDER_H_ |
#define KERN_BYTEORDER_H_ |
#include <arch/byteorder.h> |
#include <arch/types.h> |
#if !(defined(__BE__) ^ defined(__LE__)) |
#error The architecture must be either big-endian or little-endian. |
#if !(defined(ARCH_IS_BIG_ENDIAN) ^ defined(ARCH_IS_LITTLE_ENDIAN)) |
#error The architecture must be either big-endian or little-endian. |
#endif |
#ifdef __BE__ |
#ifdef ARCH_IS_BIG_ENDIAN |
#define uint16_t_le2host(n) (uint16_t_byteorder_swap(n)) |
#define uint32_t_le2host(n) (uint32_t_byteorder_swap(n)) |
#define uint64_t_le2host(n) (uint64_t_byteorder_swap(n)) |
#define uint16_t_le2host(n) uint16_t_byteorder_swap(n) |
#define uint32_t_le2host(n) uint32_t_byteorder_swap(n) |
#define uint64_t_le2host(n) uint64_t_byteorder_swap(n) |
#define uint16_t_be2host(n) (n) |
#define uint32_t_be2host(n) (n) |
#define uint64_t_be2host(n) (n) |
#define uint16_t_be2host(n) (n) |
#define uint32_t_be2host(n) (n) |
#define uint64_t_be2host(n) (n) |
#define host2uint16_t_le(n) (uint16_t_byteorder_swap(n)) |
#define host2uint32_t_le(n) (uint32_t_byteorder_swap(n)) |
#define host2uint64_t_le(n) (uint64_t_byteorder_swap(n)) |
#define host2uint16_t_le(n) uint16_t_byteorder_swap(n) |
#define host2uint32_t_le(n) uint32_t_byteorder_swap(n) |
#define host2uint64_t_le(n) uint64_t_byteorder_swap(n) |
#define host2uint16_t_be(n) (n) |
#define host2uint32_t_be(n) (n) |
#define host2uint64_t_be(n) (n) |
#define host2uint16_t_be(n) (n) |
#define host2uint32_t_be(n) (n) |
#define host2uint64_t_be(n) (n) |
#else |
#define uint16_t_le2host(n) (n) |
#define uint32_t_le2host(n) (n) |
#define uint64_t_le2host(n) (n) |
#define uint16_t_le2host(n) (n) |
#define uint32_t_le2host(n) (n) |
#define uint64_t_le2host(n) (n) |
#define uint16_t_be2host(n) (uint16_t_byteorder_swap(n)) |
#define uint32_t_be2host(n) (uint32_t_byteorder_swap(n)) |
#define uint64_t_be2host(n) (uint64_t_byteorder_swap(n)) |
#define uint16_t_be2host(n) uint16_t_byteorder_swap(n) |
#define uint32_t_be2host(n) uint32_t_byteorder_swap(n) |
#define uint64_t_be2host(n) uint64_t_byteorder_swap(n) |
#define host2uint16_t_le(n) (n) |
#define host2uint32_t_le(n) (n) |
#define host2uint64_t_le(n) (n) |
#define host2uint16_t_le(n) (n) |
#define host2uint32_t_le(n) (n) |
#define host2uint64_t_le(n) (n) |
#define host2uint16_t_be(n) (uint16_t_byteorder_swap(n)) |
#define host2uint32_t_be(n) (uint32_t_byteorder_swap(n)) |
#define host2uint64_t_be(n) (uint64_t_byteorder_swap(n)) |
#define host2uint16_t_be(n) uint16_t_byteorder_swap(n) |
#define host2uint32_t_be(n) uint32_t_byteorder_swap(n) |
#define host2uint64_t_be(n) uint64_t_byteorder_swap(n) |
#endif |
/branches/dd/kernel/generic/include/context.h |
---|
45,7 → 45,7 |
(c)->sp = ((uintptr_t) (stack)) + (size) - SP_DELTA; |
#endif /* context_set */ |
extern int context_save_arch(context_t *c) __attribute__ ((returns_twice)); |
extern int context_save_arch(context_t *c); |
extern void context_restore_arch(context_t *c) __attribute__ ((noreturn)); |
/** Save register context. |
76,6 → 76,10 |
* corresponding call to context_save(), the only |
* difference being return value. |
* |
* Note that content of any local variable defined by |
* the caller of context_save() is undefined after |
* context_restore(). |
* |
* @param c Context structure. |
*/ |
static inline void context_restore(context_t *c) |
/branches/dd/kernel/generic/src/main/uinit.c |
---|
79,14 → 79,6 |
uarg.uspace_thread_arg = NULL; |
free((uspace_arg_t *) arg); |
/* |
* Disable interrupts so that the execution of userspace() is not |
* disturbed by any interrupts as some of the userspace() |
* implementations will switch to the userspace stack before switching |
* the mode. |
*/ |
(void) interrupts_disable(); |
userspace(&uarg); |
} |
/branches/dd/kernel/generic/src/printf/printf_core.c |
---|
302,6 → 302,9 |
if (str == NULL) |
return printf_putstr(nullstr, ps); |
if (*str == U_BOM) |
str++; |
/* Print leading spaces. */ |
size_t strw = wstr_length(str); |
if (precision == 0) |
/branches/dd/kernel/arch/sparc64/include/atomic.h |
---|
123,7 → 123,7 |
"ldx %0, %2\n" |
"brz %2, 0b\n" |
"nop\n" |
"ba %%xcc, 1b\n" |
"ba %xcc, 1b\n" |
"nop\n" |
"2:\n" |
: "+m" (*((uint64_t *) x)), "+r" (tmp1), "+r" (tmp2) : "r" (0) |
/branches/dd/kernel/arch/sparc64/include/byteorder.h |
---|
0,0 → 1,43 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup sparc64 |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_sparc64_BYTEORDER_H_ |
#define KERN_sparc64_BYTEORDER_H_ |
#define ARCH_IS_BIG_ENDIAN |
#endif |
/** @} |
*/ |
/branches/dd/kernel/arch/sparc64/include/context.h |
---|
39,7 → 39,7 |
#include <arch/types.h> |
#include <align.h> |
#define SP_DELTA (STACK_WINDOW_SAVE_AREA_SIZE + STACK_ARG_SAVE_AREA_SIZE) |
#define SP_DELTA STACK_WINDOW_SAVE_AREA_SIZE |
#ifdef context_set |
#undef context_set |
/branches/dd/kernel/arch/sparc64/src/asm.S |
---|
277,7 → 277,7 |
*/ |
.global switch_to_userspace |
switch_to_userspace: |
save %o1, -(STACK_WINDOW_SAVE_AREA_SIZE + STACK_ARG_SAVE_AREA_SIZE), %sp |
save %o1, -STACK_WINDOW_SAVE_AREA_SIZE, %sp |
flushw |
wrpr %g0, 0, %cleanwin ! avoid information leak |
/branches/dd/kernel/arch/sparc64/Makefile.inc |
---|
40,8 → 40,7 |
LFLAGS += -no-check-sections -N |
BITS = 64 |
ENDIANESS = BE |
DEFS += -D__64_BITS__ |
ifeq ($(PROCESSOR),us) |
DEFS += -DUS |
/branches/dd/kernel/arch/ia64/include/mm/tlb.h |
---|
92,7 → 92,6 |
extern void data_dirty_bit_fault(uint64_t vector, istate_t *istate); |
extern void instruction_access_bit_fault(uint64_t vector, istate_t *istate); |
extern void data_access_bit_fault(uint64_t vector, istate_t *istate); |
extern void data_access_rights_fault(uint64_t vector, istate_t *istate); |
extern void page_not_present(uint64_t vector, istate_t *istate); |
#endif |
/branches/dd/kernel/arch/ia64/include/atomic.h |
---|
52,12 → 52,12 |
return v; |
} |
static inline uint64_t test_and_set(atomic_t *val) |
{ |
static inline uint64_t test_and_set(atomic_t *val) { |
uint64_t v; |
asm volatile ( |
"movl %0 = 0x1;;\n" |
"movl %0 = 0x01;;\n" |
"xchg8 %0 = %1, %0;;\n" |
: "=r" (v), "+m" (val->count) |
); |
65,13 → 65,6 |
return v; |
} |
static inline void atomic_lock_arch(atomic_t *val) |
{ |
do { |
while (val->count) |
; |
} while (test_and_set(val)); |
} |
static inline void atomic_inc(atomic_t *val) |
{ |
/branches/dd/kernel/arch/ia64/include/byteorder.h |
---|
0,0 → 1,44 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup ia64 |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_ia64_BYTEORDER_H_ |
#define KERN_ia64_BYTEORDER_H_ |
/* IA-64 is little-endian */ |
#define ARCH_IS_LITTLE_ENDIAN |
#endif |
/** @} |
*/ |
/branches/dd/kernel/arch/ia64/src/mm/tlb.c |
---|
710,37 → 710,6 |
page_table_unlock(AS, true); |
} |
/** Data access rights fault handler. |
* |
* @param vector Interruption vector. |
* @param istate Structure with saved interruption state. |
*/ |
void data_access_rights_fault(uint64_t vector, istate_t *istate) |
{ |
region_register rr; |
rid_t rid; |
uintptr_t va; |
pte_t *t; |
va = istate->cr_ifa; /* faulting address */ |
rr.word = rr_read(VA2VRN(va)); |
rid = rr.map.rid; |
/* |
* Assume a write to a read-only page. |
*/ |
page_table_lock(AS, true); |
t = page_mapping_find(AS, va); |
ASSERT(t && t->p); |
ASSERT(!t->w); |
if (as_page_fault(va, PF_ACCESS_WRITE, istate) == AS_PF_FAULT) { |
fault_if_from_uspace(istate, "Page fault at %p.", va); |
panic("%s: va=%p, rid=%d, iip=%p.", __func__, va, rid, |
istate->cr_iip); |
} |
page_table_unlock(AS, true); |
} |
/** Page not present fault handler. |
* |
* @param vector Interruption vector. |
/branches/dd/kernel/arch/ia64/src/ivt.S |
---|
536,7 → 536,7 |
HEAVYWEIGHT_HANDLER 0x5000 page_not_present |
HEAVYWEIGHT_HANDLER 0x5100 |
HEAVYWEIGHT_HANDLER 0x5200 |
HEAVYWEIGHT_HANDLER 0x5300 data_access_rights_fault |
HEAVYWEIGHT_HANDLER 0x5300 |
HEAVYWEIGHT_HANDLER 0x5400 general_exception |
HEAVYWEIGHT_HANDLER 0x5500 disabled_fp_register |
HEAVYWEIGHT_HANDLER 0x5600 |
/branches/dd/kernel/arch/ia64/Makefile.inc |
---|
41,8 → 41,7 |
LFLAGS += -EL |
AFLAGS += -mconstant-gp |
BITS = 64 |
ENDIANESS = LE |
DEFS += -D__64_BITS__ |
ARCH_SOURCES = \ |
arch/$(KARCH)/src/start.S \ |
/branches/dd/kernel/arch/arm32/include/byteorder.h |
---|
0,0 → 1,48 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup arm32 |
* @{ |
*/ |
/** @file |
* @brief Endianness definitions. |
*/ |
#ifndef KERN_arm32_BYTEORDER_H_ |
#define KERN_arm32_BYTEORDER_H_ |
#ifdef BIG_ENDIAN |
#define ARCH_IS_BIG_ENDIAN |
#else |
#define ARCH_IS_LITTLE_ENDIAN |
#endif |
#endif |
/** @} |
*/ |
/branches/dd/kernel/arch/arm32/Makefile.inc |
---|
39,8 → 39,7 |
GCC_CFLAGS += -fno-zero-initialized-in-bss |
BITS = 32 |
ENDIANESS = LE |
DEFS += -D__32_BITS__ |
ARCH_SOURCES = \ |
arch/$(KARCH)/src/start.S \ |
/branches/dd/kernel/arch/ppc32/include/byteorder.h |
---|
0,0 → 1,43 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup ppc32 |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_ppc32_BYTEORDER_H_ |
#define KERN_ppc32_BYTEORDER_H_ |
#define ARCH_IS_BIG_ENDIAN |
#endif |
/** @} |
*/ |
/branches/dd/kernel/arch/ppc32/src/ppc32.c |
---|
36,7 → 36,6 |
#include <arch.h> |
#include <arch/boot/boot.h> |
#include <genarch/drivers/via-cuda/cuda.h> |
#include <genarch/kbrd/kbrd.h> |
#include <arch/interrupt.h> |
#include <genarch/fb/fb.h> |
#include <genarch/fb/visuals.h> |
118,6 → 117,31 |
/* Initialize IRQ routing */ |
irq_init(IRQ_COUNT, IRQ_COUNT); |
if (bootinfo.macio.addr) { |
/* Initialize PIC */ |
cir_t cir; |
void *cir_arg; |
pic_init(bootinfo.macio.addr, PAGE_SIZE, &cir, &cir_arg); |
#ifdef CONFIG_VIA_CUDA |
uintptr_t pa = bootinfo.macio.addr + 0x16000; |
uintptr_t aligned_addr = ALIGN_DOWN(pa, PAGE_SIZE); |
size_t offset = pa - aligned_addr; |
size_t size = 2 * PAGE_SIZE; |
cuda_t *cuda = (cuda_t *) |
(hw_map(aligned_addr, offset + size) + offset); |
/* Initialize I/O controller */ |
cuda_instance_t *cuda_instance = |
cuda_init(cuda, IRQ_CUDA, cir, cir_arg); |
if (cuda_instance) { |
indev_t *sink = stdin_wire(); |
cuda_wire(cuda_instance, sink); |
} |
#endif |
} |
/* Merge all zones to 1 big zone */ |
zone_merge_all(); |
} |
133,35 → 157,6 |
void arch_post_smp_init(void) |
{ |
if (bootinfo.macio.addr) { |
/* Initialize PIC */ |
cir_t cir; |
void *cir_arg; |
pic_init(bootinfo.macio.addr, PAGE_SIZE, &cir, &cir_arg); |
#ifdef CONFIG_MAC_KBD |
uintptr_t pa = bootinfo.macio.addr + 0x16000; |
uintptr_t aligned_addr = ALIGN_DOWN(pa, PAGE_SIZE); |
size_t offset = pa - aligned_addr; |
size_t size = 2 * PAGE_SIZE; |
cuda_t *cuda = (cuda_t *) |
(hw_map(aligned_addr, offset + size) + offset); |
/* Initialize I/O controller */ |
cuda_instance_t *cuda_instance = |
cuda_init(cuda, IRQ_CUDA, cir, cir_arg); |
if (cuda_instance) { |
kbrd_instance_t *kbrd_instance = kbrd_init(); |
if (kbrd_instance) { |
indev_t *sink = stdin_wire(); |
indev_t *kbrd = kbrd_wire(kbrd_instance, sink); |
cuda_wire(cuda_instance, kbrd); |
pic_enable_interrupt(IRQ_CUDA); |
} |
} |
#endif |
} |
} |
void calibrate_delay_loop(void) |
/branches/dd/kernel/arch/ppc32/Makefile.inc |
---|
39,8 → 39,7 |
AFLAGS += -a32 |
LFLAGS += -no-check-sections -N |
BITS = 32 |
ENDIANESS = BE |
DEFS += -D__32_BITS__ |
ARCH_SOURCES = \ |
arch/$(KARCH)/src/context.S \ |
/branches/dd/kernel/arch/amd64/include/byteorder.h |
---|
0,0 → 1,44 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup amd64 |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_amd64_BYTEORDER_H_ |
#define KERN_amd64_BYTEORDER_H_ |
/* AMD64 is little-endian */ |
#define ARCH_IS_LITTLE_ENDIAN |
#endif |
/** @} |
*/ |
/branches/dd/kernel/arch/amd64/Makefile.inc |
---|
41,8 → 41,7 |
ICC_CFLAGS += $(CMN1) |
SUNCC_CFLAGS += -m64 -xmodel=kernel |
BITS = 64 |
ENDIANESS = LE |
DEFS += -D__64_BITS__ |
## Accepted CPUs |
# |
/branches/dd/kernel/arch/mips32/include/elf.h |
---|
26,7 → 26,7 |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup mips32 |
/** @addtogroup mips32 |
* @{ |
*/ |
/** @file |
35,15 → 35,17 |
#ifndef KERN_mips32_ELF_H_ |
#define KERN_mips32_ELF_H_ |
#define ELF_MACHINE EM_MIPS |
#include <byteorder.h> |
#ifdef __BE__ |
#define ELF_DATA_ENCODING ELFDATA2MSB |
#define ELF_MACHINE EM_MIPS |
#ifdef ARCH_IS_BIG_ENDIAN |
# define ELF_DATA_ENCODING ELFDATA2MSB |
#else |
#define ELF_DATA_ENCODING ELFDATA2LSB |
# define ELF_DATA_ENCODING ELFDATA2LSB |
#endif |
#define ELF_CLASS ELFCLASS32 |
#define ELF_CLASS ELFCLASS32 |
#endif |
/branches/dd/kernel/arch/mips32/include/context_offset.h |
---|
86,7 → 86,7 |
#define EOFFSET_STATUS 0x58 |
#define EOFFSET_EPC 0x5c |
#define EOFFSET_K1 0x60 |
#define REGISTER_SPACE 104 /* respect stack alignment */ |
#define REGISTER_SPACE 100 |
#ifdef __ASM__ |
/branches/dd/kernel/arch/mips32/include/byteorder.h |
---|
0,0 → 1,47 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup mips32 |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_mips32_BYTEORDER_H_ |
#define KERN_mips32_BYTEORDER_H_ |
#ifdef BIG_ENDIAN |
#define ARCH_IS_BIG_ENDIAN |
#else |
#define ARCH_IS_LITTLE_ENDIAN |
#endif |
#endif |
/** @} |
*/ |
/branches/dd/kernel/arch/mips32/Makefile.inc |
---|
36,7 → 36,7 |
GCC_CFLAGS += -mno-abicalls -G 0 -fno-zero-initialized-in-bss -mips3 |
BITS = 32 |
DEFS += -D__32_BITS__ |
## Accepted MACHINEs |
# |
43,18 → 43,15 |
ifeq ($(MACHINE),lgxemul) |
BFD_NAME = elf32-tradlittlemips |
ENDIANESS = LE |
endif |
ifeq ($(MACHINE),bgxemul) |
BFD_NAME = elf32-tradbigmips |
TOOLCHAIN_DIR = $(CROSS_PREFIX)/mips |
TARGET = mips-linux-gnu |
ENDIANESS = BE |
GCC_CFLAGS += -D__BE__ |
GCC_CFLAGS += -DBIG_ENDIAN |
endif |
ifeq ($(MACHINE),msim) |
BFD_NAME = elf32-tradlittlemips |
ENDIANESS = LE |
GCC_CFLAGS += -mhard-float |
endif |
/branches/dd/kernel/arch/ia32/include/byteorder.h |
---|
0,0 → 1,44 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup ia32 |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_ia32_BYTEORDER_H_ |
#define KERN_ia32_BYTEORDER_H_ |
/* IA-32 is little-endian */ |
#define ARCH_IS_LITTLE_ENDIAN |
#endif |
/** @} |
*/ |
/branches/dd/kernel/arch/ia32/Makefile.inc |
---|
35,8 → 35,7 |
TARGET = i686-pc-linux-gnu |
TOOLCHAIN_DIR = $(CROSS_PREFIX)/i686 |
BITS = 32 |
ENDIANESS = LE |
DEFS += -D__32_BITS__ |
CMN1 = -m32 |
GCC_CFLAGS += $(CMN1) |
/branches/dd/kernel/Makefile |
---|
44,12 → 44,12 |
## Common compiler flags |
# |
DEFS = -DKERNEL -DRELEASE=$(RELEASE) "-DNAME=$(NAME)" -D__$(BITS)_BITS__ -D__$(ENDIANESS)__ |
DEFS = -DKERNEL -DRELEASE=$(RELEASE) "-DNAME=$(NAME)" |
GCC_CFLAGS = -I$(INCLUDES) -O$(OPTIMIZATION) -imacros ../config.h \ |
-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32$(ENDIANESS) \ |
-finput-charset=UTF-8 -fno-builtin -Wall -Wextra -Wno-unused-parameter \ |
-Wmissing-prototypes -Werror -nostdlib -nostdinc -pipe |
-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32 -finput-charset=UTF-8 \ |
-fno-builtin -Wall -Wextra -Wno-unused-parameter -Wmissing-prototypes -Werror \ |
-nostdlib -nostdinc -pipe |
ICC_CFLAGS = -I$(INCLUDES) -O$(OPTIMIZATION) -imacros ../config.h \ |
-fno-builtin -Wall -Wmissing-prototypes -Werror \ |
/branches/dd/kernel/doc/mm |
---|
5,10 → 5,10 |
1.1 Hierarchical 4-level per address space page tables |
SPARTAN kernel deploys generic interface for 4-level page tables for these |
architectures: amd64, arm32, ia32, mips32 and ppc32. In this setting, page |
tables are hierarchical and are not shared by address spaces (i.e. one set of |
page tables per address space). |
SPARTAN kernel deploys generic interface for 4-level page tables |
for these architectures: amd64, ia32, mips32 and ppc32. In this |
setting, page tables are hierarchical and are not shared by |
address spaces (i.e. one set of page tables per address space). |
VADDR |
/branches/dd/HelenOS.config |
---|
396,9 → 396,6 |
% Sun keyboard support |
! [(CONFIG_HID_IN=generic|CONFIG_HID_IN=keyboard)&PLATFORM=sparc64&MACHINE=generic&(CONFIG_NS16550=y|CONFIG_Z8530=y)] CONFIG_SUN_KBD (y) |
% Macintosh ADB keyboard support |
! [(CONFIG_HID_IN=generic|CONFIG_HID_IN=keyboard)&PLATFORM=ppc32&(CONFIG_VIA_CUDA=y)] CONFIG_MAC_KBD (y) |
% Dummy serial line input |
! [CONFIG_MIPS_KBD=y|CONFIG_ARM_KBD=y] CONFIG_DSRLNIN (y) |
459,9 → 456,3 |
% External ramdisk |
! [PLATFORM=sparc64] CONFIG_RD_EXTERNAL (y/n) |
% Load disk drivers on startup |
! CONFIG_START_BD (n/y) |
% Mount /data on startup |
! [CONFIG_START_BD=y] CONFIG_MOUNT_DATA (n/y) |
/branches/dd/defaults/ppc32/Makefile.config |
---|
36,9 → 36,3 |
# Use Block Address Translation by the loader |
CONFIG_BAT = y |
# Load disk drivers on startup |
CONFIG_START_BD = n |
# Mount /data on startup |
CONFIG_MOUNT_DATA = n |
/branches/dd/defaults/amd64/Makefile.config |
---|
54,9 → 54,3 |
# Default framebuffer depth |
CONFIG_VESA_BPP = 16 |
# Load disk drivers on startup |
CONFIG_START_BD = n |
# Mount /data on startup |
CONFIG_MOUNT_DATA = n |
/branches/dd/defaults/ia32/Makefile.config |
---|
60,9 → 60,3 |
# Default framebuffer depth |
CONFIG_VESA_BPP = 16 |
# Load disk drivers on startup |
CONFIG_START_BD = n |
# Mount /data on startup |
CONFIG_MOUNT_DATA = n |
/branches/dd/defaults/sparc64/Makefile.config |
---|
54,9 → 54,3 |
# External ramdisk |
CONFIG_RD_EXTERNAL = y |
# Load disk drivers on startup |
CONFIG_START_BD = n |
# Mount /data on startup |
CONFIG_MOUNT_DATA = n |
/branches/dd/defaults/ia64/Makefile.config |
---|
42,9 → 42,3 |
# Output device class |
CONFIG_HID_OUT = generic |
# Load disk drivers on startup |
CONFIG_START_BD = n |
# Mount /data on startup |
CONFIG_MOUNT_DATA = n |
/branches/dd/defaults/arm32/Makefile.config |
---|
30,9 → 30,3 |
# What is your output device? |
CONFIG_HID_OUT = generic |
# Load disk drivers on startup |
CONFIG_START_BD = n |
# Mount /data on startup |
CONFIG_MOUNT_DATA = n |
/branches/dd/defaults/mips32/Makefile.config |
---|
36,9 → 36,3 |
# Output device class |
CONFIG_HID_OUT = generic |
# Load disk drivers on startup |
CONFIG_START_BD = n |
# Mount /data on startup |
CONFIG_MOUNT_DATA = n |
/branches/dd/contrib/conf/ia32-qe.sh |
---|
File deleted |
Property changes: |
Deleted: svn:executable |
-* |
\ No newline at end of property |
/branches/dd/contrib/conf/mips32-gx.sh |
---|
1,10 → 1,3 |
#!/bin/sh |
DISK_IMG=hdisk.img |
# Create a disk image if it does not exist |
if [ ! -f "$DISK_IMG" ]; then |
tools/mkfat.py uspace/dist/data "$DISK_IMG" |
fi |
gxemul $@ -E testmips -C R4000 -X image.boot -d d0:"$DISK_IMG" |
gxemul $@ -E testmips -C R4000 -X image.boot |