/branches/tracing/uspace/lib/libc/generic/kbd.c |
---|
File deleted |
/branches/tracing/uspace/lib/libc/generic/libadt/hash_table.c |
---|
File deleted |
/branches/tracing/uspace/lib/libc/generic/libadt/list.c |
---|
File deleted |
/branches/tracing/uspace/lib/libc/generic/console.c |
---|
File deleted |
/branches/tracing/uspace/lib/libc/generic/ddi.c |
---|
127,10 → 127,10 |
} |
#endif |
phys = ALIGN_DOWN((uintptr_t) pio_addr, PAGE_SIZE); |
phys = (void *) ALIGN_DOWN((uintptr_t) pio_addr, PAGE_SIZE); |
offset = pio_addr - phys; |
pages = ALIGN_UP(offset + size, PAGE_SIZE) >> PAGE_WIDTH; |
virt = as_get_mappable_page(pages); |
virt = as_get_mappable_page(pages << PAGE_WIDTH); |
*use_addr = virt + offset; |
return physmem_map(phys, virt, pages, AS_AREA_READ | AS_AREA_WRITE); |
} |
/branches/tracing/uspace/lib/libc/generic/task.c |
---|
31,7 → 31,7 |
* @{ |
*/ |
/** @file |
*/ |
*/ |
#include <task.h> |
#include <libc.h> |
39,21 → 39,25 |
#include <errno.h> |
#include <loader/loader.h> |
#include <string.h> |
#include <ipc/ns.h> |
#include <macros.h> |
#include <async.h> |
task_id_t task_get_id(void) |
{ |
task_id_t task_id; |
(void) __SYSCALL1(SYS_TASK_GET_ID, (sysarg_t) &task_id); |
return task_id; |
} |
/** Set the task name. |
* |
* @param name The new name, typically the command used to execute the |
* program. |
* @return Zero on success or negative error code. |
* @param name The new name, typically the command used to execute the |
* program. |
* |
* @return Zero on success or negative error code. |
* |
*/ |
int task_set_name(const char *name) |
{ |
65,58 → 69,102 |
* This is really just a convenience wrapper over the more complicated |
* loader API. |
* |
* @param path pathname of the binary to execute |
* @param argv command-line arguments |
* @return ID of the newly created task or zero on error. |
* @param path pathname of the binary to execute |
* @param argv command-line arguments |
* |
* @return ID of the newly created task or zero on error. |
* |
*/ |
task_id_t task_spawn(const char *path, char *const argv[]) |
task_id_t task_spawn(const char *path, char *const args[]) |
{ |
loader_t *ldr; |
task_id_t task_id; |
int rc; |
/* Connect to a program loader. */ |
ldr = loader_connect(); |
loader_t *ldr = loader_connect(); |
if (ldr == NULL) |
return 0; |
/* Get task ID. */ |
rc = loader_get_task_id(ldr, &task_id); |
task_id_t task_id; |
int rc = loader_get_task_id(ldr, &task_id); |
if (rc != EOK) |
goto error; |
/* Send program pathname. */ |
rc = loader_set_pathname(ldr, path); |
if (rc != EOK) |
goto error; |
/* Send arguments. */ |
rc = loader_set_args(ldr, argv); |
rc = loader_set_args(ldr, args); |
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) |
goto error; |
/* Run it. */ |
rc = loader_run(ldr); |
if (rc != EOK) |
goto error; |
/* Success */ |
free(ldr); |
return task_id; |
error: |
/* Error exit */ |
error: |
loader_abort(ldr); |
free(ldr); |
return 0; |
} |
int task_wait(task_id_t id, task_exit_t *texit, int *retval) |
{ |
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; |
} |
int task_retval(int val) |
{ |
return (int) async_req_1_0(PHONE_NS, NS_RETVAL, val); |
} |
/** @} |
*/ |
/branches/tracing/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 */ |
char *optarg; /* argument associated with option */ |
const char *optarg; /* argument associated with option */ |
#define IGNORE_FIRST (*options == '-' || *options == '+') |
162,7 → 162,7 |
char **nargv; |
const char *options; |
{ |
char *oli; /* option letter list index */ |
const 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,7 → 353,8 |
retval = getopt_internal(nargc, (char **)nargv, options); |
if (retval == -2) { |
char *current_argv, *has_equal; |
char *current_argv; |
const char *has_equal; |
size_t current_argv_len; |
int i, ambiguous, match; |
/branches/tracing/uspace/lib/libc/generic/fibril_sync.c |
---|
0,0 → 1,219 |
/* |
* Copyright (c) 2009 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 libc |
* @{ |
*/ |
/** @file |
*/ |
#include <fibril_sync.h> |
#include <fibril.h> |
#include <async.h> |
#include <adt/list.h> |
#include <futex.h> |
#include <assert.h> |
void fibril_mutex_initialize(fibril_mutex_t *fm) |
{ |
fm->counter = 1; |
list_initialize(&fm->waiters); |
} |
void fibril_mutex_lock(fibril_mutex_t *fm) |
{ |
futex_down(&async_futex); |
if (fm->counter-- <= 0) { |
fibril_t *f = (fibril_t *) fibril_get_id(); |
list_append(&f->link, &fm->waiters); |
fibril_switch(FIBRIL_TO_MANAGER); |
} else { |
futex_up(&async_futex); |
} |
} |
bool fibril_mutex_trylock(fibril_mutex_t *fm) |
{ |
bool locked = false; |
futex_down(&async_futex); |
if (fm->counter > 0) { |
fm->counter--; |
locked = true; |
} |
futex_up(&async_futex); |
return locked; |
} |
static void _fibril_mutex_unlock_unsafe(fibril_mutex_t *fm) |
{ |
assert(fm->counter <= 0); |
if (fm->counter++ < 0) { |
link_t *tmp; |
fibril_t *f; |
assert(!list_empty(&fm->waiters)); |
tmp = fm->waiters.next; |
f = list_get_instance(tmp, fibril_t, link); |
list_remove(&f->link); |
fibril_add_ready((fid_t) f); |
} |
} |
void fibril_mutex_unlock(fibril_mutex_t *fm) |
{ |
futex_down(&async_futex); |
_fibril_mutex_unlock_unsafe(fm); |
futex_up(&async_futex); |
} |
void fibril_rwlock_initialize(fibril_rwlock_t *frw) |
{ |
frw->writers = 0; |
frw->readers = 0; |
list_initialize(&frw->waiters); |
} |
void fibril_rwlock_read_lock(fibril_rwlock_t *frw) |
{ |
futex_down(&async_futex); |
if (frw->writers) { |
fibril_t *f = (fibril_t *) fibril_get_id(); |
f->flags &= ~FIBRIL_WRITER; |
list_append(&f->link, &frw->waiters); |
fibril_switch(FIBRIL_TO_MANAGER); |
} else { |
frw->readers++; |
futex_up(&async_futex); |
} |
} |
void fibril_rwlock_write_lock(fibril_rwlock_t *frw) |
{ |
futex_down(&async_futex); |
if (frw->writers || frw->readers) { |
fibril_t *f = (fibril_t *) fibril_get_id(); |
f->flags |= FIBRIL_WRITER; |
list_append(&f->link, &frw->waiters); |
fibril_switch(FIBRIL_TO_MANAGER); |
} else { |
frw->writers++; |
futex_up(&async_futex); |
} |
} |
static void _fibril_rwlock_common_unlock(fibril_rwlock_t *frw) |
{ |
futex_down(&async_futex); |
assert(frw->readers || (frw->writers == 1)); |
if (frw->readers) { |
if (--frw->readers) |
goto out; |
} else { |
frw->writers--; |
} |
assert(!frw->readers && !frw->writers); |
while (!list_empty(&frw->waiters)) { |
link_t *tmp = frw->waiters.next; |
fibril_t *f = list_get_instance(tmp, fibril_t, link); |
if (f->flags & FIBRIL_WRITER) { |
if (frw->readers) |
break; |
list_remove(&f->link); |
fibril_add_ready((fid_t) f); |
frw->writers++; |
break; |
} else { |
list_remove(&f->link); |
fibril_add_ready((fid_t) f); |
frw->readers++; |
} |
} |
out: |
futex_up(&async_futex); |
} |
void fibril_rwlock_read_unlock(fibril_rwlock_t *frw) |
{ |
_fibril_rwlock_common_unlock(frw); |
} |
void fibril_rwlock_write_unlock(fibril_rwlock_t *frw) |
{ |
_fibril_rwlock_common_unlock(frw); |
} |
void fibril_condvar_initialize(fibril_condvar_t *fcv) |
{ |
list_initialize(&fcv->waiters); |
} |
void fibril_condvar_wait(fibril_condvar_t *fcv, fibril_mutex_t *fm) |
{ |
fibril_t *f = (fibril_t *) fibril_get_id(); |
futex_down(&async_futex); |
list_append(&f->link, &fcv->waiters); |
_fibril_mutex_unlock_unsafe(fm); |
fibril_switch(FIBRIL_TO_MANAGER); |
fibril_mutex_lock(fm); |
} |
static void _fibril_condvar_wakeup_common(fibril_condvar_t *fcv, bool once) |
{ |
link_t *tmp; |
fibril_t *f; |
futex_down(&async_futex); |
while (!list_empty(&fcv->waiters)) { |
tmp = fcv->waiters.next; |
f = list_get_instance(tmp, fibril_t, link); |
list_remove(&f->link); |
fibril_add_ready((fid_t) f); |
if (once) |
break; |
} |
futex_up(&async_futex); |
} |
void fibril_condvar_signal(fibril_condvar_t *fcv) |
{ |
_fibril_condvar_wakeup_common(fcv, true); |
} |
void fibril_condvar_broadcast(fibril_condvar_t *fcv) |
{ |
_fibril_condvar_wakeup_common(fcv, false); |
} |
/** @} |
*/ |
/branches/tracing/uspace/lib/libc/generic/as.c |
---|
30,7 → 30,7 |
* @{ |
*/ |
/** @file |
*/ |
*/ |
#include <as.h> |
#include <libc.h> |
38,23 → 38,23 |
#include <align.h> |
#include <sys/types.h> |
#include <bitops.h> |
#include <malloc.h> |
/** |
* Either 4*256M on 32-bit architecures or 16*256M on 64-bit architectures. |
*/ |
#define MAX_HEAP_SIZE (sizeof(uintptr_t)<<28) |
/** Last position allocated by as_get_mappable_page */ |
static uintptr_t last_allocated = 0; |
/** 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,15 → 61,16 |
/** 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); |
} |
76,22 → 77,24 |
/** 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) |
{ |
99,101 → 102,29 |
(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 && -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 sz Requested size of the allocation. |
* @param size 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 sz) |
void *as_get_mappable_page(size_t size) |
{ |
void *res; |
uint64_t asz; |
int i; |
if (size == 0) |
return NULL; |
if (!sz) |
return NULL; |
asz = 1 << (fnzb64(sz - 1) + 1); |
/* Set heapsize to some meaningful value */ |
if (maxheapsize == -1) |
set_maxheapsize(MAX_HEAP_SIZE); |
size_t sz = 1 << (fnzb(size - 1) + 1); |
if (last_allocated == 0) |
last_allocated = get_max_heap_addr(); |
/* |
* Make sure we allocate from naturally aligned address. |
*/ |
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; |
uintptr_t res = ALIGN_UP(last_allocated, sz); |
last_allocated = res + ALIGN_UP(size, PAGE_SIZE); |
return ((void *) res); |
} |
/** @} |
/branches/tracing/uspace/lib/libc/generic/loader.c |
---|
30,7 → 30,7 |
* @{ |
*/ |
/** @file |
*/ |
*/ |
#include <ipc/ipc.h> |
#include <ipc/loader.h> |
47,9 → 47,12 |
/** Connect to a new program loader. |
* |
* Spawns a new program loader task and returns the connection structure. |
* @param name Symbolic name to set on the newly created task. |
* @return Pointer to the loader connection structure (should be |
* de-allocated using free() after use). |
* |
* @param name Symbolic name to set on the newly created task. |
* |
* @return Pointer to the loader connection structure (should be |
* deallocated using free() after use). |
* |
*/ |
int loader_spawn(const char *name) |
{ |
59,19 → 62,16 |
loader_t *loader_connect(void) |
{ |
loader_t *ldr; |
int phone_id; |
phone_id = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_LOAD, 0, 0); |
int phone_id = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_LOAD, 0, 0); |
if (phone_id < 0) |
return NULL; |
ldr = malloc(sizeof(loader_t)); |
loader_t *ldr = malloc(sizeof(loader_t)); |
if (ldr == NULL) |
return NULL; |
ldr->phone_id = phone_id; |
return ldr; |
return ldr; |
} |
/** Get ID of the new task. |
78,27 → 78,26 |
* |
* Retrieves the ID of the new task from the loader. |
* |
* @param ldr Loader connection structure. |
* @param task_id Points to a variable where the ID should be stored. |
* @return Zero on success or negative error code. |
* @param ldr Loader connection structure. |
* @param task_id Points to a variable where the ID should be stored. |
* |
* @return Zero on success or negative error code. |
* |
*/ |
int loader_get_task_id(loader_t *ldr, task_id_t *task_id) |
{ |
/* Get task ID. */ |
ipc_call_t answer; |
aid_t req; |
int rc; |
ipcarg_t retval; |
/* Get task ID. */ |
req = async_send_0(ldr->phone_id, LOADER_GET_TASKID, &answer); |
rc = ipc_data_read_start(ldr->phone_id, task_id, sizeof(task_id_t)); |
aid_t req = async_send_0(ldr->phone_id, LOADER_GET_TASKID, &answer); |
int rc = ipc_data_read_start(ldr->phone_id, task_id, sizeof(task_id_t)); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
return rc; |
} |
ipcarg_t retval; |
async_wait_for(req, &retval); |
return (int)retval; |
return (int) retval; |
} |
/** Set pathname of the program to load. |
107,39 → 106,35 |
* to the current working directory (it will be absolutized before |
* sending to the loader). |
* |
* @param ldr Loader connection structure. |
* @param path Pathname of the program file. |
* @return Zero on success or negative error code. |
* @param ldr Loader connection structure. |
* @param path Pathname of the program file. |
* |
* @return Zero on success or negative error code. |
* |
*/ |
int loader_set_pathname(loader_t *ldr, const char *path) |
{ |
ipc_call_t answer; |
aid_t req; |
int rc; |
ipcarg_t retval; |
char *pa; |
size_t pa_len; |
pa = absolutize(path, &pa_len); |
char *pa = absolutize(path, &pa_len); |
if (!pa) |
return 0; |
/* Send program pathname */ |
req = async_send_0(ldr->phone_id, LOADER_SET_PATHNAME, &answer); |
rc = ipc_data_write_start(ldr->phone_id, (void *)pa, pa_len); |
ipc_call_t answer; |
aid_t req = async_send_0(ldr->phone_id, LOADER_SET_PATHNAME, &answer); |
int rc = ipc_data_write_start(ldr->phone_id, (void *) pa, pa_len); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
return rc; |
} |
free(pa); |
ipcarg_t retval; |
async_wait_for(req, &retval); |
return (int)retval; |
return (int) retval; |
} |
/** Set command-line arguments for the program. |
* |
* Sets the vector of command-line arguments to be passed to the loaded |
146,61 → 141,110 |
* program. By convention, the very first argument is typically the same as |
* the command used to execute the program. |
* |
* @param ldr Loader connection structure. |
* @param argv NULL-terminated array of pointers to arguments. |
* @return Zero on success or negative error code. |
* @param ldr Loader connection structure. |
* @param argv NULL-terminated array of pointers to arguments. |
* |
* @return Zero on success or negative error code. |
* |
*/ |
int loader_set_args(loader_t *ldr, char *const argv[]) |
{ |
aid_t req; |
ipc_call_t answer; |
ipcarg_t rc; |
char *const *ap; |
char *dp; |
char *arg_buf; |
size_t buffer_size; |
/* |
/* |
* Serialize the arguments into a single array. First |
* compute size of the buffer needed. |
*/ |
ap = argv; |
buffer_size = 0; |
char *const *ap = argv; |
size_t buffer_size = 0; |
while (*ap != NULL) { |
buffer_size += str_size(*ap) + 1; |
++ap; |
ap++; |
} |
arg_buf = malloc(buffer_size); |
if (arg_buf == NULL) return ENOMEM; |
char *arg_buf = malloc(buffer_size); |
if (arg_buf == NULL) |
return ENOMEM; |
/* Now fill the buffer with null-terminated argument strings */ |
ap = argv; |
dp = arg_buf; |
char *dp = arg_buf; |
while (*ap != NULL) { |
str_cpy(dp, buffer_size - (dp - arg_buf), *ap); |
dp += str_size(*ap) + 1; |
++ap; |
ap++; |
} |
/* Send serialized arguments to the loader */ |
req = async_send_0(ldr->phone_id, LOADER_SET_ARGS, &answer); |
rc = ipc_data_write_start(ldr->phone_id, (void *)arg_buf, buffer_size); |
ipc_call_t answer; |
aid_t req = async_send_0(ldr->phone_id, LOADER_SET_ARGS, &answer); |
ipcarg_t rc = ipc_data_write_start(ldr->phone_id, (void *) arg_buf, buffer_size); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
return rc; |
} |
async_wait_for(req, &rc); |
if (rc != EOK) return rc; |
if (rc != EOK) |
return rc; |
/* Free temporary buffer */ |
free(arg_buf); |
return EOK; |
} |
/** Set preset files for the program. |
* |
* Sets the vector of preset files to be passed to the loaded |
* program. By convention, the first three files represent stdin, |
* stdout and stderr respectively. |
* |
* @param ldr Loader connection structure. |
* @param files NULL-terminated array of pointers to files. |
* |
* @return Zero on success or negative error code. |
* |
*/ |
int loader_set_files(loader_t *ldr, fdi_node_t *const files[]) |
{ |
/* |
* Serialize the arguments into a single array. First |
* compute size of the buffer needed. |
*/ |
fdi_node_t *const *ap = files; |
size_t count = 0; |
while (*ap != NULL) { |
count++; |
ap++; |
} |
fdi_node_t *files_buf; |
files_buf = (fdi_node_t *) malloc(count * sizeof(fdi_node_t)); |
if (files_buf == NULL) |
return ENOMEM; |
/* Fill the buffer */ |
size_t i; |
for (i = 0; i < count; i++) |
files_buf[i] = *files[i]; |
/* Send serialized files to the loader */ |
ipc_call_t answer; |
aid_t req = async_send_0(ldr->phone_id, LOADER_SET_FILES, &answer); |
ipcarg_t rc = ipc_data_write_start(ldr->phone_id, (void *) files_buf, |
count * sizeof(fdi_node_t)); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
return rc; |
} |
async_wait_for(req, &rc); |
if (rc != EOK) |
return rc; |
/* Free temporary buffer */ |
free(files_buf); |
return EOK; |
} |
209,18 → 253,14 |
* If this function succeeds, the program has been successfully loaded |
* and is ready to be executed. |
* |
* @param ldr Loader connection structure. |
* @return Zero on success or negative error code. |
* @param ldr Loader connection structure. |
* |
* @return Zero on success or negative error code. |
* |
*/ |
int loader_load_program(loader_t *ldr) |
{ |
int rc; |
rc = async_req_0_0(ldr->phone_id, LOADER_LOAD); |
if (rc != EOK) |
return rc; |
return EOK; |
return (int) async_req_0_0(ldr->phone_id, LOADER_LOAD); |
} |
/** Instruct loader to execute the program. |
232,17 → 272,17 |
* After using this function, no further operations must be performed |
* on the loader structure. It should be de-allocated using free(). |
* |
* @param ldr Loader connection structure. |
* @return Zero on success or negative error code. |
* @param ldr Loader connection structure. |
* |
* @return Zero on success or negative error code. |
* |
*/ |
int loader_run(loader_t *ldr) |
{ |
int rc; |
rc = async_req_0_0(ldr->phone_id, LOADER_RUN); |
int rc = async_req_0_0(ldr->phone_id, LOADER_RUN); |
if (rc != EOK) |
return rc; |
ipc_hangup(ldr->phone_id); |
ldr->phone_id = 0; |
return EOK; |
254,8 → 294,10 |
* After using this function, no further operations must be performed |
* on the loader structure. It should be de-allocated using free(). |
* |
* @param ldr Loader connection structure. |
* @return Zero on success or negative error code. |
* @param ldr Loader connection structure. |
* |
* @return Zero on success or negative error code. |
* |
*/ |
void loader_abort(loader_t *ldr) |
{ |
/branches/tracing/uspace/lib/libc/generic/string.c |
---|
138,8 → 138,8 |
* @param size Size of the output buffer (in bytes). |
* |
* @return EOK if the character was encoded successfully, EOVERFLOW if there |
* was not enough space in the output buffer or EINVAL if the character |
* code was invalid. |
* was not enough space in the output buffer or EINVAL if the character |
* code was invalid. |
*/ |
int chr_encode(const wchar_t ch, char *str, size_t *offset, size_t size) |
{ |
243,9 → 243,9 |
* @return Number of bytes used by the characters. |
* |
*/ |
size_t str_lsize(const char *str, count_t max_len) |
size_t str_lsize(const char *str, size_t max_len) |
{ |
count_t len = 0; |
size_t len = 0; |
size_t offset = 0; |
while (len < max_len) { |
271,7 → 271,7 |
* @return Number of bytes used by the wide characters. |
* |
*/ |
size_t wstr_lsize(const wchar_t *str, count_t max_len) |
size_t wstr_lsize(const wchar_t *str, size_t max_len) |
{ |
return (wstr_nlength(str, max_len * sizeof(wchar_t)) * sizeof(wchar_t)); |
} |
283,9 → 283,9 |
* @return Number of characters in string. |
* |
*/ |
count_t str_length(const char *str) |
size_t str_length(const char *str) |
{ |
count_t len = 0; |
size_t len = 0; |
size_t offset = 0; |
while (str_decode(str, &offset, STR_NO_LIMIT) != 0) |
301,9 → 301,9 |
* @return Number of characters in @a str. |
* |
*/ |
count_t wstr_length(const wchar_t *wstr) |
size_t wstr_length(const wchar_t *wstr) |
{ |
count_t len = 0; |
size_t len = 0; |
while (*wstr++ != 0) |
len++; |
319,9 → 319,9 |
* @return Number of characters in string. |
* |
*/ |
count_t str_nlength(const char *str, size_t size) |
size_t str_nlength(const char *str, size_t size) |
{ |
count_t len = 0; |
size_t len = 0; |
size_t offset = 0; |
while (str_decode(str, &offset, size) != 0) |
338,11 → 338,11 |
* @return Number of characters in string. |
* |
*/ |
count_t wstr_nlength(const wchar_t *str, size_t size) |
size_t wstr_nlength(const wchar_t *str, size_t size) |
{ |
count_t len = 0; |
count_t limit = ALIGN_DOWN(size, sizeof(wchar_t)); |
count_t offset = 0; |
size_t len = 0; |
size_t limit = ALIGN_DOWN(size, sizeof(wchar_t)); |
size_t offset = 0; |
while ((offset < limit) && (*str++ != 0)) { |
len++; |
430,7 → 430,7 |
* 1 if second smaller. |
* |
*/ |
int str_lcmp(const char *s1, const char *s2, count_t max_len) |
int str_lcmp(const char *s1, const char *s2, size_t max_len) |
{ |
wchar_t c1 = 0; |
wchar_t c2 = 0; |
438,7 → 438,7 |
size_t off1 = 0; |
size_t off2 = 0; |
count_t len = 0; |
size_t len = 0; |
while (true) { |
if (len >= max_len) |
568,7 → 568,7 |
return; |
wchar_t ch; |
count_t src_idx = 0; |
size_t src_idx = 0; |
size_t dst_off = 0; |
while ((ch = src[src_idx++]) != 0) { |
589,7 → 589,7 |
* |
* @return Pointer to character in @a str or NULL if not found. |
*/ |
const char *str_chr(const char *str, wchar_t ch) |
char *str_chr(const char *str, wchar_t ch) |
{ |
wchar_t acc; |
size_t off = 0; |
597,7 → 597,7 |
while ((acc = str_decode(str, &off, STR_NO_LIMIT)) != 0) { |
if (acc == ch) |
return (str + last); |
return (char *) (str + last); |
last = off; |
} |
611,12 → 611,12 |
* |
* @return Pointer to character in @a str or NULL if not found. |
*/ |
const char *str_rchr(const char *str, wchar_t ch) |
char *str_rchr(const char *str, wchar_t ch) |
{ |
wchar_t acc; |
size_t off = 0; |
size_t last = 0; |
char *res = NULL; |
const char *res = NULL; |
while ((acc = str_decode(str, &off, STR_NO_LIMIT)) != 0) { |
if (acc == ch) |
624,7 → 624,7 |
last = off; |
} |
return res; |
return (char *) res; |
} |
/** Insert a wide character into a wide string. |
641,14 → 641,14 |
* is out of bounds. |
* |
*/ |
bool wstr_linsert(wchar_t *str, wchar_t ch, count_t pos, count_t max_pos) |
bool wstr_linsert(wchar_t *str, wchar_t ch, size_t pos, size_t max_pos) |
{ |
count_t len = wstr_length(str); |
size_t len = wstr_length(str); |
if ((pos > len) || (pos + 1 > max_pos)) |
return false; |
count_t i; |
size_t i; |
for (i = len; i + 1 > pos; i--) |
str[i + 1] = str[i]; |
669,14 → 669,14 |
* is out of bounds. |
* |
*/ |
bool wstr_remove(wchar_t *str, count_t pos) |
bool wstr_remove(wchar_t *str, size_t pos) |
{ |
count_t len = wstr_length(str); |
size_t len = wstr_length(str); |
if (pos >= len) |
return false; |
count_t i; |
size_t i; |
for (i = pos + 1; i <= len; i++) |
str[i - 1] = str[i]; |
/branches/tracing/uspace/lib/libc/generic/malloc.c |
---|
0,0 → 1,475 |
/* |
* Copyright (c) 2009 Martin Decky |
* Copyright (c) 2009 Petr Tuma |
* 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 libc |
* @{ |
*/ |
/** @file |
*/ |
#include <malloc.h> |
#include <bool.h> |
#include <as.h> |
#include <align.h> |
#include <macros.h> |
#include <assert.h> |
#include <errno.h> |
#include <bitops.h> |
#include <mem.h> |
#include <adt/gcdlcm.h> |
/* Magic used in heap headers. */ |
#define HEAP_BLOCK_HEAD_MAGIC 0xBEEF0101 |
/* Magic used in heap footers. */ |
#define HEAP_BLOCK_FOOT_MAGIC 0xBEEF0202 |
/** Allocation alignment (this also covers the alignment of fields |
in the heap header and footer) */ |
#define BASE_ALIGN 16 |
/** |
* Either 4 * 256M on 32-bit architecures or 16 * 256M on 64-bit architectures |
*/ |
#define MAX_HEAP_SIZE (sizeof(uintptr_t) << 28) |
/** |
* |
*/ |
#define STRUCT_OVERHEAD (sizeof(heap_block_head_t) + sizeof(heap_block_foot_t)) |
/** |
* Calculate real size of a heap block (with header and footer) |
*/ |
#define GROSS_SIZE(size) ((size) + STRUCT_OVERHEAD) |
/** |
* Calculate net size of a heap block (without header and footer) |
*/ |
#define NET_SIZE(size) ((size) - STRUCT_OVERHEAD) |
/** Header of a heap block |
* |
*/ |
typedef struct { |
/* Size of the block (including header and footer) */ |
size_t size; |
/* Indication of a free block */ |
bool free; |
/* A magic value to detect overwrite of heap header */ |
uint32_t magic; |
} heap_block_head_t; |
/** Footer of a heap block |
* |
*/ |
typedef struct { |
/* Size of the block (including header and footer) */ |
size_t size; |
/* A magic value to detect overwrite of heap footer */ |
uint32_t magic; |
} heap_block_foot_t; |
/** Linker heap symbol */ |
extern char _heap; |
/** Address of heap start */ |
static void *heap_start = 0; |
/** Address of heap end */ |
static void *heap_end = 0; |
/** Maximum heap size */ |
static size_t max_heap_size = (size_t) -1; |
/** Current number of pages of heap area */ |
static size_t heap_pages = 0; |
/** Initialize a heap block |
* |
* Fills in the structures related to a heap block. |
* |
* @param addr Address of the block. |
* @param size Size of the block including the header and the footer. |
* @param free Indication of a free block. |
* |
*/ |
static void block_init(void *addr, size_t size, bool free) |
{ |
/* Calculate the position of the header and the footer */ |
heap_block_head_t *head = (heap_block_head_t *) addr; |
heap_block_foot_t *foot = |
(heap_block_foot_t *) (addr + size - sizeof(heap_block_foot_t)); |
head->size = size; |
head->free = free; |
head->magic = HEAP_BLOCK_HEAD_MAGIC; |
foot->size = size; |
foot->magic = HEAP_BLOCK_FOOT_MAGIC; |
} |
/** Check a heap block |
* |
* Verifies that the structures related to a heap block still contain |
* the magic constants. This helps detect heap corruption early on. |
* |
* @param addr Address of the block. |
* |
*/ |
static void block_check(void *addr) |
{ |
heap_block_head_t *head = (heap_block_head_t *) addr; |
assert(head->magic == HEAP_BLOCK_HEAD_MAGIC); |
heap_block_foot_t *foot = |
(heap_block_foot_t *) (addr + head->size - sizeof(heap_block_foot_t)); |
assert(foot->magic == HEAP_BLOCK_FOOT_MAGIC); |
assert(head->size == foot->size); |
} |
static bool grow_heap(size_t size) |
{ |
if (size == 0) |
return false; |
size_t heap_size = (size_t) (heap_end - heap_start); |
if ((max_heap_size != (size_t) -1) && (heap_size + size > max_heap_size)) |
return false; |
size_t pages = (size - 1) / PAGE_SIZE + 1; |
if (as_area_resize((void *) &_heap, (heap_pages + pages) * PAGE_SIZE, 0) |
== EOK) { |
void *end = (void *) ALIGN_DOWN(((uintptr_t) &_heap) + |
(heap_pages + pages) * PAGE_SIZE, BASE_ALIGN); |
block_init(heap_end, end - heap_end, true); |
heap_pages += pages; |
heap_end = end; |
return true; |
} |
return false; |
} |
static void shrink_heap(void) |
{ |
// TODO |
} |
/** Initialize the heap allocator |
* |
* Finds how much physical memory we have and creates |
* the heap management structures that mark the whole |
* physical memory as a single free block. |
* |
*/ |
void __heap_init(void) |
{ |
if (as_area_create((void *) &_heap, PAGE_SIZE, |
AS_AREA_WRITE | AS_AREA_READ)) { |
heap_pages = 1; |
heap_start = (void *) ALIGN_UP((uintptr_t) &_heap, BASE_ALIGN); |
heap_end = |
(void *) ALIGN_DOWN(((uintptr_t) &_heap) + PAGE_SIZE, BASE_ALIGN); |
/* Make the entire area one large block. */ |
block_init(heap_start, heap_end - heap_start, true); |
} |
} |
uintptr_t get_max_heap_addr(void) |
{ |
if (max_heap_size == (size_t) -1) |
max_heap_size = |
max((size_t) (heap_end - heap_start), MAX_HEAP_SIZE); |
return ((uintptr_t) heap_start + max_heap_size); |
} |
static void split_mark(heap_block_head_t *cur, const size_t size) |
{ |
assert(cur->size >= size); |
/* See if we should split the block. */ |
size_t split_limit = GROSS_SIZE(size); |
if (cur->size > split_limit) { |
/* Block big enough -> split. */ |
void *next = ((void *) cur) + size; |
block_init(next, cur->size - size, true); |
block_init(cur, size, false); |
} else { |
/* Block too small -> use as is. */ |
cur->free = false; |
} |
} |
/** Allocate a memory block |
* |
* @param size The size of the block to allocate. |
* @param align Memory address alignment. |
* |
* @return the address of the block or NULL when not enough memory. |
* |
*/ |
static void *malloc_internal(const size_t size, const size_t align) |
{ |
if (align == 0) |
return NULL; |
size_t falign = lcm(align, BASE_ALIGN); |
size_t real_size = GROSS_SIZE(ALIGN_UP(size, falign)); |
bool grown = false; |
void *result; |
loop: |
result = NULL; |
heap_block_head_t *cur = (heap_block_head_t *) heap_start; |
while ((result == NULL) && ((void *) cur < heap_end)) { |
block_check(cur); |
/* Try to find a block that is free and large enough. */ |
if ((cur->free) && (cur->size >= real_size)) { |
/* We have found a suitable block. |
Check for alignment properties. */ |
void *addr = ((void *) cur) + sizeof(heap_block_head_t); |
void *aligned = (void *) ALIGN_UP(addr, falign); |
if (addr == aligned) { |
/* Exact block start including alignment. */ |
split_mark(cur, real_size); |
result = addr; |
} else { |
/* Block start has to be aligned */ |
size_t excess = (size_t) (aligned - addr); |
if (cur->size >= real_size + excess) { |
/* The current block is large enough to fit |
data in including alignment */ |
if ((void *) cur > heap_start) { |
/* There is a block before the current block. |
This previous block can be enlarged to compensate |
for the alignment excess */ |
heap_block_foot_t *prev_foot = |
((void *) cur) - sizeof(heap_block_foot_t); |
heap_block_head_t *prev_head = |
(heap_block_head_t *) (((void *) cur) - prev_foot->size); |
block_check(prev_head); |
size_t reduced_size = cur->size - excess; |
heap_block_head_t *next_head = ((void *) cur) + excess; |
if ((!prev_head->free) && (excess >= STRUCT_OVERHEAD)) { |
/* The previous block is not free and there is enough |
space to fill in a new free block between the previous |
and current block */ |
block_init(cur, excess, true); |
} else { |
/* The previous block is free (thus there is no need to |
induce additional fragmentation to the heap) or the |
excess is small, thus just enlarge the previous block */ |
block_init(prev_head, prev_head->size + excess, prev_head->free); |
} |
block_init(next_head, reduced_size, true); |
split_mark(next_head, real_size); |
result = aligned; |
cur = next_head; |
} else { |
/* The current block is the first block on the heap. |
We have to make sure that the alignment excess |
is large enough to fit a new free block just |
before the current block */ |
while (excess < STRUCT_OVERHEAD) { |
aligned += falign; |
excess += falign; |
} |
/* Check for current block size again */ |
if (cur->size >= real_size + excess) { |
size_t reduced_size = cur->size - excess; |
cur = (heap_block_head_t *) (heap_start + excess); |
block_init(heap_start, excess, true); |
block_init(cur, reduced_size, true); |
split_mark(cur, real_size); |
result = aligned; |
} |
} |
} |
} |
} |
/* Advance to the next block. */ |
cur = (heap_block_head_t *) (((void *) cur) + cur->size); |
} |
if ((result == NULL) && (!grown)) { |
if (grow_heap(real_size)) { |
grown = true; |
goto loop; |
} |
} |
return result; |
} |
void *malloc(const size_t size) |
{ |
return malloc_internal(size, BASE_ALIGN); |
} |
void *memalign(const size_t align, const size_t size) |
{ |
if (align == 0) |
return NULL; |
size_t palign = |
1 << (fnzb(max(sizeof(void *), align) - 1) + 1); |
return malloc_internal(size, palign); |
} |
void *realloc(const void *addr, const size_t size) |
{ |
if (addr == NULL) |
return malloc(size); |
/* Calculate the position of the header. */ |
heap_block_head_t *head = |
(heap_block_head_t *) (addr - sizeof(heap_block_head_t)); |
assert((void *) head >= heap_start); |
assert((void *) head < heap_end); |
block_check(head); |
assert(!head->free); |
void *ptr = NULL; |
size_t real_size = GROSS_SIZE(ALIGN_UP(size, BASE_ALIGN)); |
size_t orig_size = head->size; |
if (orig_size > real_size) { |
/* Shrink */ |
if (orig_size - real_size >= STRUCT_OVERHEAD) { |
/* Split the original block to a full block |
and a tailing free block */ |
block_init((void *) head, real_size, false); |
block_init((void *) head + real_size, |
orig_size - real_size, true); |
shrink_heap(); |
} |
ptr = ((void *) head) + sizeof(heap_block_head_t); |
} else { |
/* Look at the next block. If it is free and the size is |
sufficient then merge the two. */ |
heap_block_head_t *next_head = |
(heap_block_head_t *) (((void *) head) + head->size); |
if (((void *) next_head < heap_end) && |
(head->size + next_head->size >= real_size) && |
(next_head->free)) { |
block_check(next_head); |
block_init(head, head->size + next_head->size, false); |
split_mark(head, real_size); |
ptr = ((void *) head) + sizeof(heap_block_head_t); |
} else { |
ptr = malloc(size); |
if (ptr != NULL) { |
memcpy(ptr, addr, NET_SIZE(orig_size)); |
free(addr); |
} |
} |
} |
return ptr; |
} |
/** Free a memory block |
* |
* @param addr The address of the block. |
*/ |
void free(const void *addr) |
{ |
/* Calculate the position of the header. */ |
heap_block_head_t *head |
= (heap_block_head_t *) (addr - sizeof(heap_block_head_t)); |
assert((void *) head >= heap_start); |
assert((void *) head < heap_end); |
block_check(head); |
assert(!head->free); |
/* Mark the block itself as free. */ |
head->free = true; |
/* Look at the next block. If it is free, merge the two. */ |
heap_block_head_t *next_head |
= (heap_block_head_t *) (((void *) head) + head->size); |
if ((void *) next_head < heap_end) { |
block_check(next_head); |
if (next_head->free) |
block_init(head, head->size + next_head->size, true); |
} |
/* Look at the previous block. If it is free, merge the two. */ |
if ((void *) head > heap_start) { |
heap_block_foot_t *prev_foot = |
(heap_block_foot_t *) (((void *) head) - sizeof(heap_block_foot_t)); |
heap_block_head_t *prev_head = |
(heap_block_head_t *) (((void *) head) - prev_foot->size); |
block_check(prev_head); |
if (prev_head->free) |
block_init(prev_head, prev_head->size + head->size, true); |
} |
shrink_heap(); |
} |
/** @} |
*/ |
/branches/tracing/uspace/lib/libc/generic/fibril.c |
---|
33,7 → 33,7 |
/** @file |
*/ |
#include <libadt/list.h> |
#include <adt/list.h> |
#include <fibril.h> |
#include <thread.h> |
#include <tls.h> |
49,7 → 49,8 |
#define FIBRIL_INITIAL_STACK_PAGES_NO 1 |
#endif |
/** This futex serializes access to ready_list, serialized_list and manage_list. |
/** |
* This futex serializes access to ready_list, serialized_list and manager_list. |
*/ |
static atomic_t fibril_futex = FUTEX_INITIALIZER; |
59,12 → 60,12 |
static void fibril_main(void); |
/** Number of fibrils that are in async_serialized mode */ |
static int serialized_fibrils; /* Protected by async_futex */ |
/** Thread-local count of serialization. If >0, we must not preempt */ |
static __thread int serialization_count; |
/** Counter for fibrils residing in async_manager */ |
static int fibrils_in_manager; |
/** Number of threads that are executing a manager fibril. */ |
static int threads_in_manager; |
/** Number of threads that are executing a manager fibril and are serialized. */ |
static int serialized_threads; /* Protected by async_futex */ |
/** Fibril-local count of serialization. If > 0, we must not preempt */ |
static fibril_local int serialization_count; |
/** Setup fibril information into TCB structure */ |
fibril_t *fibril_setup(void) |
143,11 → 144,11 |
if (list_empty(&ready_list) && list_empty(&serialized_list)) |
goto ret_0; |
/* |
* Do not preempt if there is not sufficient count of fibril |
* managers. |
* Do not preempt if there is not enough threads to run the |
* ready fibrils which are not serialized. |
*/ |
if (list_empty(&serialized_list) && |
fibrils_in_manager <= serialized_fibrils) { |
threads_in_manager <= serialized_threads) { |
goto ret_0; |
} |
} |
194,7 → 195,7 |
list_append(&srcf->link, &ready_list); |
else if (stype == FIBRIL_FROM_MANAGER) { |
list_append(&srcf->link, &manager_list); |
fibrils_in_manager--; |
threads_in_manager--; |
} else { |
/* |
* If stype == FIBRIL_TO_MANAGER, don't put ourselves to |
208,10 → 209,10 |
if (stype == FIBRIL_TO_MANAGER || stype == FIBRIL_FROM_DEAD) { |
dstf = list_get_instance(manager_list.next, fibril_t, link); |
if (serialization_count && stype == FIBRIL_TO_MANAGER) { |
serialized_fibrils++; |
serialized_threads++; |
srcf->flags |= FIBRIL_SERIALIZED; |
} |
fibrils_in_manager++; |
threads_in_manager++; |
if (stype == FIBRIL_FROM_DEAD) |
dstf->clean_after_me = srcf; |
219,7 → 220,7 |
if (!list_empty(&serialized_list)) { |
dstf = list_get_instance(serialized_list.next, fibril_t, |
link); |
serialized_fibrils--; |
serialized_threads--; |
} else { |
dstf = list_get_instance(ready_list.next, fibril_t, |
link); |
269,7 → 270,7 |
/** Add a fibril to the ready list. |
* |
* @param fid Pinter to the fibril structure of the fibril to be |
* @param fid Pointer to the fibril structure of the fibril to be |
* added. |
*/ |
void fibril_add_ready(fid_t fid) |
287,7 → 288,8 |
/** Add a fibril to the manager list. |
* |
* @param fid Pinter to the fibril structure of the fibril to be added. |
* @param fid Pointer to the fibril structure of the fibril to be |
* added. |
*/ |
void fibril_add_manager(fid_t fid) |
{ |
314,7 → 316,8 |
/** Return fibril id of the currently running fibril. |
* |
* @return Fibril ID of the currently running pseudo thread. |
* @return fibril ID of the currently running fibril. |
* |
*/ |
fid_t fibril_get_id(void) |
{ |
321,13 → 324,14 |
return (fid_t) __tcb_get()->fibril_data; |
} |
/** Disable preemption |
/** Disable preemption |
* |
* If the fibril wants to send several message in a row and does not want to be |
* preempted, it should start async_serialize_start() in the beginning of |
* communication and async_serialize_end() in the end. If it is a true |
* multithreaded application, it should protect the communication channel by a |
* futex as well. Interrupt messages can still be preempted. |
* futex as well. |
* |
*/ |
void fibril_inc_sercount(void) |
{ |
/branches/tracing/uspace/lib/libc/generic/libc.c |
---|
27,35 → 27,33 |
*/ |
/** @addtogroup lc Libc |
* @brief HelenOS C library |
* @brief HelenOS C library |
* @{ |
* @} |
*/ |
/** @addtogroup libc generic |
* @ingroup lc |
* @{ |
*/ |
/** @file |
*/ |
*/ |
#include <libc.h> |
#include <stdio.h> |
#include <unistd.h> |
#include <malloc.h> |
#include <tls.h> |
#include <thread.h> |
#include <fibril.h> |
#include <io/stream.h> |
#include <ipc/ipc.h> |
#include <async.h> |
#include <as.h> |
#include <console.h> |
#include <loader/pcb.h> |
extern char _heap; |
extern int main(int argc, char *argv[]); |
int _errno; |
void _exit(int status) |
{ |
thread_exit(status); |
63,28 → 61,33 |
void __main(void *pcb_ptr) |
{ |
fibril_t *f; |
int retval; |
__heap_init(); |
__async_init(); |
fibril_t *fibril = fibril_setup(); |
__tcb_set(fibril->tcb); |
/* Save the PCB pointer */ |
__pcb = (pcb_t *) pcb_ptr; |
int argc; |
char **argv; |
(void) as_area_create(&_heap, 1, AS_AREA_WRITE | AS_AREA_READ); |
_async_init(); |
f = fibril_setup(); |
__tcb_set(f->tcb); |
/* Save the PCB pointer */ |
__pcb = (pcb_t *)pcb_ptr; |
if (__pcb == NULL) { |
argc = 0; |
argv = NULL; |
__stdio_init(0, NULL); |
} else { |
argc = __pcb->argc; |
argv = __pcb->argv; |
__stdio_init(__pcb->filc, __pcb->filv); |
} |
retval = main(argc, argv); |
main(argc, argv); |
console_flush(); |
__stdio_done(); |
(void) task_retval(retval); |
} |
void __exit(void) |
/branches/tracing/uspace/lib/libc/generic/ipc.c |
---|
43,7 → 43,7 |
#include <libc.h> |
#include <malloc.h> |
#include <errno.h> |
#include <libadt/list.h> |
#include <adt/list.h> |
#include <stdio.h> |
#include <unistd.h> |
#include <futex.h> |
232,7 → 232,7 |
return; |
} |
if (callid == IPC_CALLRET_FATAL) { |
if (callid == (ipc_callid_t) IPC_CALLRET_FATAL) { |
futex_up(&ipc_futex); |
/* Call asynchronous handler with error code */ |
if (call->callback) |
241,7 → 241,7 |
return; |
} |
if (callid == IPC_CALLRET_TEMPORARY) { |
if (callid == (ipc_callid_t) IPC_CALLRET_TEMPORARY) { |
futex_up(&ipc_futex); |
call->u.msg.phoneid = phoneid; |
309,7 → 309,7 |
callid = __SYSCALL6(SYS_IPC_CALL_ASYNC_FAST, phoneid, method, arg1, |
arg2, arg3, arg4); |
if (callid == IPC_CALLRET_TEMPORARY) { |
if (callid == (ipc_callid_t) IPC_CALLRET_TEMPORARY) { |
if (!call) { |
call = ipc_prepare_async(private, callback); |
if (!call) |
442,7 → 442,7 |
call = list_get_instance(queued_calls.next, async_call_t, list); |
callid = _ipc_call_async(call->u.msg.phoneid, |
&call->u.msg.data); |
if (callid == IPC_CALLRET_TEMPORARY) { |
if (callid == (ipc_callid_t) IPC_CALLRET_TEMPORARY) { |
break; |
} |
list_remove(&call->list); |
451,7 → 451,7 |
if (call->fid) |
fibril_add_ready(call->fid); |
if (callid == IPC_CALLRET_FATAL) { |
if (callid == (ipc_callid_t) IPC_CALLRET_FATAL) { |
if (call->callback) |
call->callback(call->private, ENOENT, NULL); |
free(call); |
704,7 → 704,7 |
IPC_SET_ARG4(data, arg4); |
IPC_SET_ARG5(data, arg5); |
return __SYSCALL3(SYS_IPC_FORWARD_SLOW, callid, (sysarg_t) &data, mode); |
return __SYSCALL4(SYS_IPC_FORWARD_SLOW, callid, phoneid, (sysarg_t) &data, mode); |
} |
/** Wrapper for making IPC_M_SHARE_IN calls. |
/branches/tracing/uspace/lib/libc/generic/devmap.c |
---|
0,0 → 1,289 |
/* |
* Copyright (c) 2007 Josef Cejka |
* Copyright (c) 2009 Jiri Svoboda |
* 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 <string.h> |
#include <ipc/ipc.h> |
#include <ipc/services.h> |
#include <ipc/devmap.h> |
#include <devmap.h> |
#include <async.h> |
#include <errno.h> |
static int devmap_phone_driver = -1; |
static int devmap_phone_client = -1; |
/** Get phone to device mapper task. */ |
int devmap_get_phone(devmap_interface_t iface, unsigned int flags) |
{ |
switch (iface) { |
case DEVMAP_DRIVER: |
if (devmap_phone_driver >= 0) |
return devmap_phone_driver; |
if (flags & IPC_FLAG_BLOCKING) |
devmap_phone_driver = ipc_connect_me_to_blocking(PHONE_NS, |
SERVICE_DEVMAP, DEVMAP_DRIVER, 0); |
else |
devmap_phone_driver = ipc_connect_me_to(PHONE_NS, |
SERVICE_DEVMAP, DEVMAP_DRIVER, 0); |
return devmap_phone_driver; |
case DEVMAP_CLIENT: |
if (devmap_phone_client >= 0) |
return devmap_phone_client; |
if (flags & IPC_FLAG_BLOCKING) |
devmap_phone_client = ipc_connect_me_to_blocking(PHONE_NS, |
SERVICE_DEVMAP, DEVMAP_CLIENT, 0); |
else |
devmap_phone_client = ipc_connect_me_to(PHONE_NS, |
SERVICE_DEVMAP, DEVMAP_CLIENT, 0); |
return devmap_phone_client; |
default: |
return -1; |
} |
} |
void devmap_hangup_phone(devmap_interface_t iface) |
{ |
switch (iface) { |
case DEVMAP_DRIVER: |
if (devmap_phone_driver >= 0) { |
ipc_hangup(devmap_phone_driver); |
devmap_phone_driver = -1; |
} |
break; |
case DEVMAP_CLIENT: |
if (devmap_phone_client >= 0) { |
ipc_hangup(devmap_phone_client); |
devmap_phone_client = -1; |
} |
break; |
default: |
break; |
} |
} |
/** Register new driver with devmap. */ |
int devmap_driver_register(const char *name, async_client_conn_t conn) |
{ |
int phone = devmap_get_phone(DEVMAP_DRIVER, IPC_FLAG_BLOCKING); |
if (phone < 0) |
return phone; |
async_serialize_start(); |
ipc_call_t answer; |
aid_t req = async_send_2(phone, DEVMAP_DRIVER_REGISTER, 0, 0, &answer); |
ipcarg_t retval = ipc_data_write_start(phone, name, str_size(name) + 1); |
if (retval != EOK) { |
async_wait_for(req, NULL); |
async_serialize_end(); |
return -1; |
} |
async_set_client_connection(conn); |
ipcarg_t callback_phonehash; |
ipc_connect_to_me(phone, 0, 0, 0, &callback_phonehash); |
async_wait_for(req, &retval); |
async_serialize_end(); |
return retval; |
} |
/** Register new device. |
* |
* @param name Device name. |
* @param handle Output: Handle to the created instance of device. |
* |
*/ |
int devmap_device_register(const char *name, dev_handle_t *handle) |
{ |
int phone = devmap_get_phone(DEVMAP_DRIVER, IPC_FLAG_BLOCKING); |
if (phone < 0) |
return phone; |
async_serialize_start(); |
ipc_call_t answer; |
aid_t req = async_send_2(phone, DEVMAP_DEVICE_REGISTER, 0, 0, |
&answer); |
ipcarg_t retval = ipc_data_write_start(phone, name, str_size(name) + 1); |
if (retval != EOK) { |
async_wait_for(req, NULL); |
async_serialize_end(); |
return retval; |
} |
async_wait_for(req, &retval); |
async_serialize_end(); |
if (retval != EOK) { |
if (handle != NULL) |
*handle = -1; |
return retval; |
} |
if (handle != NULL) |
*handle = (dev_handle_t) IPC_GET_ARG1(answer); |
return retval; |
} |
int devmap_device_get_handle(const char *name, dev_handle_t *handle, unsigned int flags) |
{ |
int phone = devmap_get_phone(DEVMAP_CLIENT, flags); |
if (phone < 0) |
return phone; |
async_serialize_start(); |
ipc_call_t answer; |
aid_t req = async_send_2(phone, DEVMAP_DEVICE_GET_HANDLE, flags, 0, |
&answer); |
ipcarg_t retval = ipc_data_write_start(phone, name, str_size(name) + 1); |
if (retval != EOK) { |
async_wait_for(req, NULL); |
async_serialize_end(); |
return retval; |
} |
async_wait_for(req, &retval); |
async_serialize_end(); |
if (retval != EOK) { |
if (handle != NULL) |
*handle = (dev_handle_t) -1; |
return retval; |
} |
if (handle != NULL) |
*handle = (dev_handle_t) IPC_GET_ARG1(answer); |
return retval; |
} |
int devmap_device_connect(dev_handle_t handle, unsigned int flags) |
{ |
int phone; |
if (flags & IPC_FLAG_BLOCKING) { |
phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_DEVMAP, |
DEVMAP_CONNECT_TO_DEVICE, handle); |
} else { |
phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP, |
DEVMAP_CONNECT_TO_DEVICE, handle); |
} |
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); |
if (phone < 0) |
return 0; |
ipcarg_t count; |
int retval = async_req_0_1(phone, DEVMAP_DEVICE_GET_COUNT, &count); |
if (retval != EOK) |
return 0; |
return count; |
} |
ipcarg_t devmap_device_get_devices(ipcarg_t count, dev_desc_t *data) |
{ |
int phone = devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING); |
if (phone < 0) |
return 0; |
async_serialize_start(); |
ipc_call_t answer; |
aid_t req = async_send_0(phone, DEVMAP_DEVICE_GET_DEVICES, &answer); |
ipcarg_t retval = ipc_data_read_start(phone, data, count * sizeof(dev_desc_t)); |
if (retval != EOK) { |
async_wait_for(req, NULL); |
async_serialize_end(); |
return 0; |
} |
async_wait_for(req, &retval); |
async_serialize_end(); |
if (retval != EOK) |
return 0; |
return IPC_GET_ARG1(answer); |
} |
/branches/tracing/uspace/lib/libc/generic/async.c |
---|
95,8 → 95,8 |
#include <async.h> |
#include <fibril.h> |
#include <stdio.h> |
#include <libadt/hash_table.h> |
#include <libadt/list.h> |
#include <adt/hash_table.h> |
#include <adt/list.h> |
#include <ipc/ipc.h> |
#include <assert.h> |
#include <errno.h> |
174,7 → 174,7 |
} connection_t; |
/** Identifier of the incoming connection handled by the current fibril. */ |
__thread connection_t *FIBRIL_connection; |
fibril_local connection_t *FIBRIL_connection; |
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); |
190,11 → 190,9 |
*/ |
static async_client_conn_t interrupt_received = default_interrupt_received; |
static hash_table_t conn_hash_table; |
static LIST_INITIALIZE(timeout_list); |
#define CONN_HASH_TABLE_CHAINS 32 |
/** Compute hash into the connection hash table based on the source phone hash. |
500,9 → 498,10 |
/* Answer all remaining messages with EHANGUP */ |
while (!list_empty(&FIBRIL_connection->msg_queue)) { |
msg_t *msg |
= list_get_instance(FIBRIL_connection->msg_queue.next, msg_t, link); |
msg_t *msg; |
msg = list_get_instance(FIBRIL_connection->msg_queue.next, |
msg_t, link); |
list_remove(&msg->link); |
ipc_answer_0(msg->callid, EHANGUP); |
free(msg); |
563,7 → 562,7 |
} |
/* Add connection to the connection hash table */ |
ipcarg_t key = conn->in_phone_hash; |
unsigned long key = conn->in_phone_hash; |
futex_down(&async_futex); |
hash_table_insert(&conn_hash_table, &key, &conn->link); |
588,23 → 587,28 |
/* Unrouted call - do some default behaviour */ |
if ((callid & IPC_CALLID_NOTIFICATION)) { |
process_notification(callid, call); |
return; |
goto out; |
} |
switch (IPC_GET_METHOD(*call)) { |
case IPC_M_CONNECT_ME: |
case IPC_M_CONNECT_ME_TO: |
/* Open new connection with fibril etc. */ |
async_new_connection(IPC_GET_ARG5(*call), callid, call, |
client_connection); |
return; |
goto out; |
} |
/* Try to route the call through the connection hash table */ |
if (route_call(callid, call)) |
return; |
goto out; |
/* Unknown call from unknown phone - hang it up */ |
ipc_answer_0(callid, EHANGUP); |
return; |
out: |
; |
} |
/** Fire all timeouts that expired. */ |
662,8 → 666,8 |
suseconds_t timeout; |
if (!list_empty(&timeout_list)) { |
awaiter_t *waiter |
= list_get_instance(timeout_list.next, awaiter_t, link); |
awaiter_t *waiter = list_get_instance(timeout_list.next, |
awaiter_t, link); |
struct timeval tv; |
gettimeofday(&tv, NULL); |
680,8 → 684,8 |
futex_up(&async_futex); |
ipc_call_t call; |
ipc_callid_t callid |
= ipc_wait_cycle(&call, timeout, SYNCH_FLAGS_NONE); |
ipc_callid_t callid = ipc_wait_cycle(&call, timeout, |
SYNCH_FLAGS_NONE); |
if (!callid) { |
handle_expired_timeouts(); |
734,7 → 738,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)) { |
758,13 → 762,13 |
*/ |
static void reply_received(void *arg, int retval, ipc_call_t *data) |
{ |
futex_down(&async_futex); |
amsg_t *msg = (amsg_t *) arg; |
msg->retval = retval; |
futex_down(&async_futex); |
/* Copy data after futex_down, just in case the call was detached */ |
if (msg->dataptr) |
if ((msg->dataptr) && (data)) |
*msg->dataptr = *data; |
write_barrier(); |
810,6 → 814,7 |
msg->done = false; |
msg->dataptr = dataptr; |
msg->wdata.inlist = false; |
/* We may sleep in the next method, but it will use its own mechanism */ |
msg->wdata.active = true; |
849,6 → 854,7 |
msg->done = false; |
msg->dataptr = dataptr; |
msg->wdata.inlist = false; |
/* We may sleep in next method, but it will use its own mechanism */ |
msg->wdata.active = true; |
/branches/tracing/uspace/lib/libc/generic/vfs/vfs.c |
---|
38,8 → 38,8 |
#include <unistd.h> |
#include <dirent.h> |
#include <fcntl.h> |
#include <stdio.h> |
#include <sys/stat.h> |
#include <stdio.h> |
#include <sys/types.h> |
#include <ipc/ipc.h> |
#include <ipc/services.h> |
48,13 → 48,14 |
#include <futex.h> |
#include <errno.h> |
#include <string.h> |
#include <devmap.h> |
#include <ipc/vfs.h> |
#include <ipc/devmap.h> |
#include "../../../srv/vfs/vfs.h" |
int vfs_phone = -1; |
futex_t vfs_phone_futex = FUTEX_INITIALIZER; |
static int vfs_phone = -1; |
static futex_t vfs_phone_futex = FUTEX_INITIALIZER; |
static futex_t cwd_futex = FUTEX_INITIALIZER; |
futex_t cwd_futex = FUTEX_INITIALIZER; |
DIR *cwd_dir = NULL; |
char *cwd_path = NULL; |
size_t cwd_size = 0; |
115,47 → 116,8 |
vfs_phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_VFS, 0, 0); |
} |
static int device_get_handle(const char *name, dev_handle_t *handle, |
const unsigned int flags) |
{ |
int phone; |
if (flags & IPC_FLAG_BLOCKING) |
phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_DEVMAP, DEVMAP_CLIENT, 0); |
else |
phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP, DEVMAP_CLIENT, 0); |
if (phone < 0) |
return phone; |
ipc_call_t answer; |
aid_t req = async_send_2(phone, DEVMAP_DEVICE_GET_HANDLE, flags, 0, |
&answer); |
ipcarg_t retval = ipc_data_write_start(phone, name, str_size(name) + 1); |
if (retval != EOK) { |
async_wait_for(req, NULL); |
ipc_hangup(phone); |
return retval; |
} |
async_wait_for(req, &retval); |
if (handle != NULL) |
*handle = -1; |
if (retval == EOK) { |
if (handle != NULL) |
*handle = (dev_handle_t) IPC_GET_ARG1(answer); |
} |
ipc_hangup(phone); |
return retval; |
} |
int mount(const char *fs_name, const char *mp, const char *dev, |
const char *opts, const unsigned int flags) |
const char *opts, unsigned int flags) |
{ |
int res; |
ipcarg_t rc; |
162,7 → 124,7 |
aid_t req; |
dev_handle_t dev_handle; |
res = device_get_handle(dev, &dev_handle, flags); |
res = devmap_device_get_handle(dev, &dev_handle, flags); |
if (res != EOK) |
return res; |
175,7 → 137,7 |
async_serialize_start(); |
vfs_connect(); |
req = async_send_2(vfs_phone, VFS_MOUNT, dev_handle, flags, NULL); |
req = async_send_2(vfs_phone, VFS_IN_MOUNT, dev_handle, flags, NULL); |
rc = ipc_data_write_start(vfs_phone, (void *) mpa, mpa_size); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
236,7 → 198,7 |
async_serialize_start(); |
vfs_connect(); |
req = async_send_3(vfs_phone, VFS_OPEN, lflag, oflag, 0, &answer); |
req = async_send_3(vfs_phone, VFS_IN_OPEN, lflag, oflag, 0, &answer); |
rc = ipc_data_write_start(vfs_phone, pa, pa_size); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
249,9 → 211,10 |
async_serialize_end(); |
futex_up(&vfs_phone_futex); |
free(pa); |
if (rc != EOK) |
return (int) rc; |
return (int) IPC_GET_ARG1(answer); |
} |
260,6 → 223,27 |
return _open(path, L_FILE, oflag); |
} |
int open_node(fdi_node_t *node, int oflag) |
{ |
futex_down(&vfs_phone_futex); |
async_serialize_start(); |
vfs_connect(); |
ipc_call_t answer; |
aid_t req = async_send_4(vfs_phone, VFS_IN_OPEN_NODE, node->fs_handle, |
node->dev_handle, node->index, oflag, &answer); |
ipcarg_t rc; |
async_wait_for(req, &rc); |
async_serialize_end(); |
futex_up(&vfs_phone_futex); |
if (rc != EOK) |
return (int) rc; |
return (int) IPC_GET_ARG1(answer); |
} |
int close(int fildes) |
{ |
ipcarg_t rc; |
268,7 → 252,7 |
async_serialize_start(); |
vfs_connect(); |
rc = async_req_1_0(vfs_phone, VFS_CLOSE, fildes); |
rc = async_req_1_0(vfs_phone, VFS_IN_CLOSE, fildes); |
async_serialize_end(); |
futex_up(&vfs_phone_futex); |
286,7 → 270,7 |
async_serialize_start(); |
vfs_connect(); |
req = async_send_1(vfs_phone, VFS_READ, fildes, &answer); |
req = async_send_1(vfs_phone, VFS_IN_READ, fildes, &answer); |
rc = ipc_data_read_start(vfs_phone, (void *)buf, nbyte); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
313,7 → 297,7 |
async_serialize_start(); |
vfs_connect(); |
req = async_send_1(vfs_phone, VFS_WRITE, fildes, &answer); |
req = async_send_1(vfs_phone, VFS_IN_WRITE, fildes, &answer); |
rc = ipc_data_write_start(vfs_phone, (void *)buf, nbyte); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
330,6 → 314,20 |
return -1; |
} |
int fsync(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); |
async_serialize_end(); |
futex_up(&vfs_phone_futex); |
return (int) rc; |
} |
off_t lseek(int fildes, off_t offset, int whence) |
{ |
ipcarg_t rc; |
339,7 → 337,7 |
vfs_connect(); |
ipcarg_t newoffs; |
rc = async_req_3_1(vfs_phone, VFS_SEEK, fildes, offset, whence, |
rc = async_req_3_1(vfs_phone, VFS_IN_SEEK, fildes, offset, whence, |
&newoffs); |
async_serialize_end(); |
359,12 → 357,74 |
async_serialize_start(); |
vfs_connect(); |
rc = async_req_2_0(vfs_phone, VFS_TRUNCATE, fildes, length); |
rc = async_req_2_0(vfs_phone, VFS_IN_TRUNCATE, fildes, length); |
async_serialize_end(); |
futex_up(&vfs_phone_futex); |
return (int) rc; |
} |
int fstat(int fildes, struct stat *stat) |
{ |
ipcarg_t rc; |
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); |
async_serialize_end(); |
futex_up(&vfs_phone_futex); |
return rc; |
} |
int stat(const char *path, struct stat *stat) |
{ |
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); |
async_serialize_end(); |
futex_up(&vfs_phone_futex); |
free(pa); |
return rc; |
} |
DIR *opendir(const char *dirname) |
{ |
DIR *dirp = malloc(sizeof(DIR)); |
412,7 → 472,7 |
async_serialize_start(); |
vfs_connect(); |
req = async_send_1(vfs_phone, VFS_MKDIR, mode, NULL); |
req = async_send_1(vfs_phone, VFS_IN_MKDIR, mode, NULL); |
rc = ipc_data_write_start(vfs_phone, pa, pa_size); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
425,7 → 485,7 |
async_serialize_end(); |
futex_up(&vfs_phone_futex); |
free(pa); |
return rc; |
return rc; |
} |
static int _unlink(const char *path, int lflag) |
442,7 → 502,7 |
async_serialize_start(); |
vfs_connect(); |
req = async_send_0(vfs_phone, VFS_UNLINK, NULL); |
req = async_send_0(vfs_phone, VFS_IN_UNLINK, NULL); |
rc = ipc_data_write_start(vfs_phone, pa, pa_size); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
455,7 → 515,7 |
async_serialize_end(); |
futex_up(&vfs_phone_futex); |
free(pa); |
return rc; |
return rc; |
} |
int unlink(const char *path) |
489,7 → 549,7 |
async_serialize_start(); |
vfs_connect(); |
req = async_send_0(vfs_phone, VFS_RENAME, NULL); |
req = async_send_0(vfs_phone, VFS_IN_RENAME, NULL); |
rc = ipc_data_write_start(vfs_phone, olda, olda_size); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
558,5 → 618,34 |
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/tracing/uspace/lib/libc/generic/mem.c |
---|
95,7 → 95,7 |
static void *unaligned_memcpy(void *dst, const void *src, size_t n) |
{ |
int i, j; |
size_t i, j; |
struct along *adst = dst; |
const struct along *asrc = src; |
/branches/tracing/uspace/lib/libc/generic/errno.c |
---|
0,0 → 1,41 |
/* |
* 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. |
*/ |
/** @addtogroup libc |
* @{ |
*/ |
/** @file |
*/ |
#include <errno.h> |
#include <fibril.h> |
int _errno; |
/** @} |
*/ |
/branches/tracing/uspace/lib/libc/generic/io/sprintf.c |
---|
File deleted |
/branches/tracing/uspace/lib/libc/generic/io/vsprintf.c |
---|
File deleted |
/branches/tracing/uspace/lib/libc/generic/io/fprintf.c |
---|
File deleted |
/branches/tracing/uspace/lib/libc/generic/io/stream.c |
---|
File deleted |
/branches/tracing/uspace/lib/libc/generic/io/stdio.c |
---|
File deleted |
/branches/tracing/uspace/lib/libc/generic/io/printf.c |
---|
34,23 → 34,43 |
#include <io/printf_core.h> |
#include <stdio.h> |
#include <stdio.h> |
/** Print formatted text. |
* @param fmt format string |
* |
* @param stream Output stream |
* @param fmt Format string |
* |
* \see For more details about format string see printf_core. |
* |
*/ |
int fprintf(FILE *stream, const char *fmt, ...) |
{ |
va_list args; |
va_start(args, fmt); |
int ret = vfprintf(stream, fmt, args); |
va_end(args); |
return ret; |
} |
/** Print formatted text to stdout. |
* |
* @param fmt Format string |
* |
* \see For more details about format string see printf_core. |
* |
*/ |
int printf(const char *fmt, ...) |
{ |
int ret; |
va_list args; |
va_start(args, fmt); |
ret = vprintf(fmt, args); |
int ret = vprintf(fmt, args); |
va_end(args); |
return ret; |
} |
/branches/tracing/uspace/lib/libc/generic/io/console.c |
---|
0,0 → 1,113 |
/* |
* Copyright (c) 2006 Josef Cejka |
* Copyright (c) 2006 Jakub Vana |
* Copyright (c) 2008 Jiri Svoboda |
* 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 libc |
* @{ |
*/ |
/** @file |
*/ |
#include <libc.h> |
#include <async.h> |
#include <io/console.h> |
#include <ipc/console.h> |
void console_clear(int phone) |
{ |
async_msg_0(phone, CONSOLE_CLEAR); |
} |
int console_get_size(int phone, ipcarg_t *rows, ipcarg_t *cols) |
{ |
return async_req_0_2(phone, CONSOLE_GET_SIZE, rows, cols); |
} |
void console_set_style(int phone, int style) |
{ |
async_msg_1(phone, CONSOLE_SET_STYLE, style); |
} |
void console_set_color(int phone, int fg_color, int bg_color, int flags) |
{ |
async_msg_3(phone, CONSOLE_SET_COLOR, fg_color, bg_color, flags); |
} |
void console_set_rgb_color(int phone, int fg_color, int bg_color) |
{ |
async_msg_2(phone, CONSOLE_SET_RGB_COLOR, fg_color, bg_color); |
} |
void console_cursor_visibility(int phone, bool show) |
{ |
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); |
} |
void console_goto(int phone, ipcarg_t row, ipcarg_t col) |
{ |
async_msg_2(phone, CONSOLE_GOTO, row, col); |
} |
bool console_get_event(int phone, console_event_t *event) |
{ |
ipcarg_t type; |
ipcarg_t key; |
ipcarg_t mods; |
ipcarg_t c; |
int rc = async_req_0_4(phone, CONSOLE_GET_EVENT, &type, &key, &mods, &c); |
if (rc < 0) |
return false; |
event->type = type; |
event->key = key; |
event->mods = mods; |
event->c = c; |
return true; |
} |
/** @} |
*/ |
/branches/tracing/uspace/lib/libc/generic/io/snprintf.c |
---|
37,21 → 37,23 |
#include <io/printf_core.h> |
/** Print formatted to the given buffer with limited size. |
* @param str buffer |
* @param size buffer size |
* @param fmt format string |
* |
* @param str Buffer |
* @param size Buffer size |
* @param fmt Format string |
* |
* \see For more details about format string see printf_core. |
* |
*/ |
int snprintf(char *str, size_t size, const char *fmt, ...) |
{ |
int ret; |
va_list args; |
va_start(args, fmt); |
va_start(args, fmt); |
ret = vsnprintf(str, size, fmt, args); |
int ret = vsnprintf(str, size, fmt, args); |
va_end(args); |
return ret; |
} |
/branches/tracing/uspace/lib/libc/generic/io/asprintf.c |
---|
36,42 → 36,52 |
#include <stdarg.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <io/printf_core.h> |
static int asprintf_prewrite(const char *str, size_t count, void *unused) |
static int asprintf_str_write(const char *str, size_t count, void *unused) |
{ |
return count; |
return str_nlength(str, count); |
} |
static int asprintf_wstr_write(const wchar_t *str, size_t count, void *unused) |
{ |
return wstr_nlength(str, count); |
} |
/** Allocate and print to string. |
* |
* @param strp Address of the pointer where to store the address of |
* the newly allocated string. |
* @fmt Format strin. |
* @param strp Address of the pointer where to store the address of |
* the newly allocated string. |
* @fmt Format string. |
* |
* @return Number of characters printed or a negative error code. |
* @return Number of characters printed or a negative error code. |
* |
*/ |
int asprintf(char **strp, const char *fmt, ...) |
{ |
struct printf_spec ps = { |
asprintf_prewrite, |
NULL |
asprintf_str_write, |
asprintf_wstr_write, |
NULL |
}; |
int ret; |
va_list args; |
va_start(args, fmt); |
ret = printf_core(fmt, &ps, args); |
int ret = printf_core(fmt, &ps, args); |
va_end(args); |
if (ret > 0) { |
*strp = malloc(ret + 20); |
if (!*strp) |
*strp = malloc(STR_BOUNDS(ret) + 1); |
if (*strp == NULL) |
return -1; |
va_start(args, fmt); |
vsprintf(*strp, fmt, args); |
va_end(args); |
vsnprintf(*strp, STR_BOUNDS(ret) + 1, fmt, args); |
va_end(args); |
} |
return ret; |
} |
/branches/tracing/uspace/lib/libc/generic/io/io.c |
---|
30,98 → 30,564 |
* @{ |
*/ |
/** @file |
*/ |
*/ |
#include <libc.h> |
#include <stdio.h> |
#include <unistd.h> |
#include <stdio.h> |
#include <io/io.h> |
#include <fcntl.h> |
#include <assert.h> |
#include <string.h> |
#include <errno.h> |
#include <console.h> |
#include <bool.h> |
#include <malloc.h> |
#include <io/klog.h> |
#include <vfs/vfs.h> |
#include <ipc/devmap.h> |
#include <adt/list.h> |
const static char nl = '\n'; |
static void _fflushbuf(FILE *stream); |
int puts(const char *str) |
static FILE stdin_null = { |
.fd = -1, |
.error = true, |
.eof = true, |
.klog = false, |
.phone = -1, |
.btype = _IONBF, |
.buf = NULL, |
.buf_size = 0, |
.buf_head = NULL |
}; |
static FILE stdout_klog = { |
.fd = -1, |
.error = false, |
.eof = false, |
.klog = true, |
.phone = -1, |
.btype = _IOLBF, |
.buf = NULL, |
.buf_size = BUFSIZ, |
.buf_head = NULL |
}; |
static FILE stderr_klog = { |
.fd = -1, |
.error = false, |
.eof = false, |
.klog = true, |
.phone = -1, |
.btype = _IONBF, |
.buf = NULL, |
.buf_size = 0, |
.buf_head = NULL |
}; |
FILE *stdin = NULL; |
FILE *stdout = NULL; |
FILE *stderr = NULL; |
static LIST_INITIALIZE(files); |
void __stdio_init(int filc, fdi_node_t *filv[]) |
{ |
size_t count; |
if (filc > 0) { |
stdin = fopen_node(filv[0], "r"); |
} else { |
stdin = &stdin_null; |
list_append(&stdin->link, &files); |
} |
if (str == NULL) |
return putnchars("(NULL)", 6); |
if (filc > 1) { |
stdout = fopen_node(filv[1], "w"); |
} else { |
stdout = &stdout_klog; |
list_append(&stdout->link, &files); |
} |
for (count = 0; str[count] != 0; count++); |
if (filc > 2) { |
stderr = fopen_node(filv[2], "w"); |
} else { |
stderr = &stderr_klog; |
list_append(&stderr->link, &files); |
} |
} |
void __stdio_done(void) |
{ |
link_t *link = files.next; |
if (console_write((void *) str, count) == count) { |
if (console_write(&nl, 1) == 1) |
return 0; |
while (link != &files) { |
FILE *file = list_get_instance(link, FILE, link); |
fclose(file); |
link = files.next; |
} |
} |
static bool parse_mode(const char *mode, int *flags) |
{ |
/* Parse mode except first character. */ |
const char *mp = mode; |
if (*mp++ == 0) { |
errno = EINVAL; |
return false; |
} |
return EOF; |
if ((*mp == 'b') || (*mp == 't')) |
mp++; |
bool plus; |
if (*mp == '+') { |
mp++; |
plus = true; |
} else |
plus = false; |
if (*mp != 0) { |
errno = EINVAL; |
return false; |
} |
/* Parse first character of mode and determine flags for open(). */ |
switch (mode[0]) { |
case 'r': |
*flags = plus ? O_RDWR : O_RDONLY; |
break; |
case 'w': |
*flags = (O_TRUNC | O_CREAT) | (plus ? O_RDWR : O_WRONLY); |
break; |
case 'a': |
/* TODO: a+ must read from beginning, append to the end. */ |
if (plus) { |
errno = ENOTSUP; |
return false; |
} |
*flags = (O_APPEND | O_CREAT) | (plus ? O_RDWR : O_WRONLY); |
default: |
errno = EINVAL; |
return false; |
} |
return true; |
} |
/** Put count chars from buffer to stdout without adding newline |
* @param buf Buffer with size at least count bytes - NULL pointer NOT allowed! |
* @param count |
* @return 0 on succes, EOF on fail |
*/ |
int putnchars(const char *buf, size_t count) |
/** Set stream buffer. */ |
void setvbuf(FILE *stream, void *buf, int mode, size_t size) |
{ |
if (console_write((void *) buf, count) == count) |
return 0; |
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. */ |
return EOF; |
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); |
} |
} |
/** Same as puts, but does not print newline at end |
/** 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. |
* @param mode Mode string, (r|w|a)[b|t][+]. |
* |
*/ |
int putstr(const char *str) |
FILE *fopen(const char *path, const char *mode) |
{ |
size_t count; |
int flags; |
if (!parse_mode(mode, &flags)) |
return NULL; |
if (str == NULL) |
return putnchars("(NULL)", 6); |
/* Open file. */ |
FILE *stream = malloc(sizeof(FILE)); |
if (stream == NULL) { |
errno = ENOMEM; |
return NULL; |
} |
stream->fd = open(path, flags, 0666); |
if (stream->fd < 0) { |
/* errno was set by open() */ |
free(stream); |
return NULL; |
} |
stream->error = false; |
stream->eof = false; |
stream->klog = false; |
stream->phone = -1; |
_setvbuf(stream); |
list_append(&stream->link, &files); |
return stream; |
} |
for (count = 0; str[count] != 0; count++); |
if (console_write((void *) str, count) == count) |
return 0; |
FILE *fdopen(int fd, const char *mode) |
{ |
/* Open file. */ |
FILE *stream = malloc(sizeof(FILE)); |
if (stream == NULL) { |
errno = ENOMEM; |
return NULL; |
} |
return EOF; |
stream->fd = fd; |
stream->error = false; |
stream->eof = false; |
stream->klog = false; |
stream->phone = -1; |
_setvbuf(stream); |
list_append(&stream->link, &files); |
return stream; |
} |
int putchar(int c) |
FILE *fopen_node(fdi_node_t *node, const char *mode) |
{ |
char buf[STR_BOUNDS(1)]; |
size_t offs; |
int flags; |
if (!parse_mode(mode, &flags)) |
return NULL; |
/* Open file. */ |
FILE *stream = malloc(sizeof(FILE)); |
if (stream == NULL) { |
errno = ENOMEM; |
return NULL; |
} |
stream->fd = open_node(node, flags); |
if (stream->fd < 0) { |
/* errno was set by open_node() */ |
free(stream); |
return NULL; |
} |
stream->error = false; |
stream->eof = false; |
stream->klog = false; |
stream->phone = -1; |
_setvbuf(stream); |
list_append(&stream->link, &files); |
return stream; |
} |
offs = 0; |
if (chr_encode(c, buf, &offs, STR_BOUNDS(1)) != EOK) |
int fclose(FILE *stream) |
{ |
int rc = 0; |
fflush(stream); |
if (stream->phone >= 0) |
ipc_hangup(stream->phone); |
if (stream->fd >= 0) |
rc = close(stream->fd); |
list_remove(&stream->link); |
if ((stream != &stdin_null) |
&& (stream != &stdout_klog) |
&& (stream != &stderr_klog)) |
free(stream); |
stream = NULL; |
if (rc != 0) { |
/* errno was set by close() */ |
return EOF; |
} |
return 0; |
} |
if (console_write((void *) buf, offs) == offs) |
return c; |
/** Read from a stream. |
* |
* @param buf Destination buffer. |
* @param size Size of each record. |
* @param nmemb Number of records to read. |
* @param stream Pointer to the stream. |
* |
*/ |
size_t fread(void *buf, size_t size, size_t nmemb, FILE *stream) |
{ |
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); |
if (rd < 0) |
stream->error = true; |
else if (rd == 0) |
stream->eof = true; |
else { |
left -= rd; |
done += rd; |
} |
} |
return (done / size); |
} |
return EOF; |
static size_t _fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream) |
{ |
size_t left = size * nmemb; |
size_t done = 0; |
while ((left > 0) && (!stream->error)) { |
ssize_t wr; |
if (stream->klog) |
wr = klog_write(buf + done, left); |
else |
wr = write(stream->fd, buf + done, left); |
if (wr <= 0) |
stream->error = true; |
else { |
left -= wr; |
done += wr; |
} |
} |
return (done / size); |
} |
int getchar(void) |
/** Drain stream buffer, do not sync stream. */ |
static void _fflushbuf(FILE *stream) |
{ |
unsigned char c; |
size_t bytes_used; |
console_flush(); |
if (read_stdin((void *) &c, 1) == 1) |
return c; |
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)]; |
size_t sz = 0; |
if (chr_encode(c, buf, &sz, STR_BOUNDS(1)) == EOK) { |
size_t wr = fwrite(buf, sz, 1, stream); |
if (wr < sz) |
return EOF; |
return (int) c; |
} |
return EOF; |
} |
int fflush(FILE *f) |
int putchar(wchar_t c) |
{ |
/* Dummy implementation */ |
(void) f; |
console_flush(); |
return fputc(c, stdout); |
} |
int fputs(const char *str, FILE *stream) |
{ |
return fwrite(str, str_size(str), 1, stream); |
} |
int puts(const char *str) |
{ |
return fputs(str, stdout); |
} |
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; |
return (int) c; |
} |
int getchar(void) |
{ |
return fgetc(stdin); |
} |
int fseek(FILE *stream, long offset, int origin) |
{ |
off_t rc = lseek(stream->fd, offset, origin); |
if (rc == (off_t) (-1)) { |
/* errno has been set by lseek. */ |
return -1; |
} |
stream->eof = false; |
return 0; |
} |
void rewind(FILE *stream) |
{ |
(void) fseek(stream, 0, SEEK_SET); |
} |
int fflush(FILE *stream) |
{ |
_fflushbuf(stream); |
if (stream->klog) { |
klog_update(); |
return EOK; |
} |
if (stream->fd >= 0) |
return fsync(stream->fd); |
return ENOENT; |
} |
int feof(FILE *stream) |
{ |
return stream->eof; |
} |
int ferror(FILE *stream) |
{ |
return stream->error; |
} |
int fphone(FILE *stream) |
{ |
if (stream->fd >= 0) { |
if (stream->phone < 0) |
stream->phone = fd_phone(stream->fd); |
return stream->phone; |
} |
return -1; |
} |
int fnode(FILE *stream, fdi_node_t *node) |
{ |
if (stream->fd >= 0) |
return fd_node(stream->fd, node); |
return ENOENT; |
} |
/** @} |
*/ |
/branches/tracing/uspace/lib/libc/generic/io/vprintf.c |
---|
38,37 → 38,25 |
#include <io/printf_core.h> |
#include <futex.h> |
#include <async.h> |
#include <console.h> |
#include <string.h> |
static atomic_t printf_futex = FUTEX_INITIALIZER; |
static int vprintf_str_write(const char *str, size_t size, void *data) |
static int vprintf_str_write(const char *str, size_t size, void *stream) |
{ |
size_t offset = 0; |
size_t prev; |
count_t chars = 0; |
while (offset < size) { |
prev = offset; |
str_decode(str, &offset, size); |
console_write(str + prev, offset - prev); |
chars++; |
} |
return chars; |
size_t wr = fwrite(str, 1, size, (FILE *) stream); |
return str_nlength(str, wr); |
} |
static int vprintf_wstr_write(const wchar_t *str, size_t size, void *data) |
static int vprintf_wstr_write(const wchar_t *str, size_t size, void *stream) |
{ |
size_t offset = 0; |
size_t boff; |
count_t chars = 0; |
char buf[4]; |
size_t chars = 0; |
while (offset < size) { |
boff = 0; |
chr_encode(str[chars], buf, &boff, 4); |
console_write(buf, boff); |
if (fputc(str[chars], (FILE *) stream) <= 0) |
break; |
chars++; |
offset += sizeof(wchar_t); |
} |
76,33 → 64,55 |
return chars; |
} |
/** Print formatted text. |
* @param fmt format string |
* @param ap format parameters |
* |
* @param stream Output stream |
* @param fmt Format string |
* @param ap Format parameters |
* |
* \see For more details about format string see printf_core. |
* |
*/ |
int vprintf(const char *fmt, va_list ap) |
int vfprintf(FILE *stream, const char *fmt, va_list ap) |
{ |
struct printf_spec ps = { |
vprintf_str_write, |
vprintf_wstr_write, |
NULL |
stream |
}; |
/* |
* Prevent other threads to execute printf_core() |
*/ |
futex_down(&printf_futex); |
/* |
* Prevent other pseudo threads of the same thread |
* Prevent other fibrils of the same thread |
* to execute printf_core() |
*/ |
async_serialize_start(); |
int ret = printf_core(fmt, &ps, ap); |
async_serialize_end(); |
futex_up(&printf_futex); |
return ret; |
} |
/** Print formatted text to stdout. |
* |
* @param file Output stream |
* @param fmt Format string |
* @param ap Format parameters |
* |
* \see For more details about format string see printf_core. |
* |
*/ |
int vprintf(const char *fmt, va_list ap) |
{ |
return vfprintf(stdout, fmt, ap); |
} |
/** @} |
*/ |
/branches/tracing/uspace/lib/libc/generic/io/vsnprintf.c |
---|
82,7 → 82,7 |
* with the trailing zero => print only a part |
* of string |
*/ |
index_t index = 0; |
size_t index = 0; |
while (index < size) { |
wchar_t uc = str_decode(str, &index, size); |
130,7 → 130,7 |
*/ |
static int vsnprintf_wstr_write(const wchar_t *str, size_t size, vsnprintf_data_t *data) |
{ |
index_t index = 0; |
size_t index = 0; |
while (index < (size / sizeof(wchar_t))) { |
size_t left = data->size - data->len; |
/branches/tracing/uspace/lib/libc/generic/io/printf_core.c |
---|
173,7 → 173,7 |
*/ |
static int print_char(const char ch, int width, uint32_t flags, printf_spec_t *ps) |
{ |
count_t counter = 0; |
size_t counter = 0; |
if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) { |
while (--width > 0) { |
/* |
211,7 → 211,7 |
*/ |
static int print_wchar(const wchar_t ch, int width, uint32_t flags, printf_spec_t *ps) |
{ |
count_t counter = 0; |
size_t counter = 0; |
if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) { |
while (--width > 0) { |
/* |
254,12 → 254,12 |
return printf_putstr(nullstr, ps); |
/* Print leading spaces. */ |
count_t strw = str_length(str); |
size_t strw = str_length(str); |
if (precision == 0) |
precision = strw; |
/* Left padding */ |
count_t counter = 0; |
size_t counter = 0; |
width -= precision; |
if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) { |
while (width-- > 0) { |
301,9 → 301,6 |
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) |
310,7 → 307,7 |
precision = strw; |
/* Left padding */ |
count_t counter = 0; |
size_t counter = 0; |
width -= precision; |
if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) { |
while (width-- > 0) { |
432,7 → 429,7 |
} |
width -= precision + size - number_size; |
count_t counter = 0; |
size_t counter = 0; |
if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) { |
while (width-- > 0) { |
595,7 → 592,7 |
size_t nxt = 0; /* Index of the next character from fmt */ |
size_t j = 0; /* Index to the first not printed nonformating character */ |
count_t counter = 0; /* Number of characters printed */ |
size_t counter = 0; /* Number of characters printed */ |
int retval; /* Return values from nested functions */ |
while (true) { |
/branches/tracing/uspace/lib/libc/generic/io/klog.c |
---|
0,0 → 1,53 |
/* |
* Copyright (c) 2006 Josef Cejka |
* Copyright (c) 2006 Jakub Vana |
* 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 libc |
* @{ |
*/ |
/** @file |
*/ |
#include <libc.h> |
#include <string.h> |
#include <sys/types.h> |
#include <unistd.h> |
#include <io/klog.h> |
size_t klog_write(const void *buf, size_t size) |
{ |
return (size_t) __SYSCALL3(SYS_KLOG, 1, (sysarg_t) buf, size); |
} |
void klog_update(void) |
{ |
(void) __SYSCALL3(SYS_KLOG, 1, NULL, 0); |
} |
/** @} |
*/ |
/branches/tracing/uspace/lib/libc/generic/adt/hash_table.c |
---|
0,0 → 1,196 |
/* |
* Copyright (c) 2008 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 libc |
* @{ |
*/ |
/** @file |
*/ |
/* |
* This is an implementation of generic chained hash table. |
*/ |
#include <adt/hash_table.h> |
#include <adt/list.h> |
#include <unistd.h> |
#include <malloc.h> |
#include <assert.h> |
#include <stdio.h> |
#include <string.h> |
/** Create chained hash table. |
* |
* @param h Hash table structure. Will be initialized by this call. |
* @param m Number of hash table buckets. |
* @param max_keys Maximal number of keys needed to identify an item. |
* @param op Hash table operations structure. |
* @return True on success |
*/ |
int hash_table_create(hash_table_t *h, hash_count_t m, hash_count_t max_keys, |
hash_table_operations_t *op) |
{ |
hash_count_t i; |
assert(h); |
assert(op && op->hash && op->compare); |
assert(max_keys > 0); |
h->entry = malloc(m * sizeof(link_t)); |
if (!h->entry) { |
printf("cannot allocate memory for hash table\n"); |
return false; |
} |
memset((void *) h->entry, 0, m * sizeof(link_t)); |
for (i = 0; i < m; i++) |
list_initialize(&h->entry[i]); |
h->entries = m; |
h->max_keys = max_keys; |
h->op = op; |
return true; |
} |
/** Destroy a hash table instance. |
* |
* @param h Hash table to be destroyed. |
*/ |
void hash_table_destroy(hash_table_t *h) |
{ |
assert(h); |
assert(h->entry); |
free(h->entry); |
} |
/** Insert item into a hash table. |
* |
* @param h Hash table. |
* @param key Array of all keys necessary to compute hash index. |
* @param item Item to be inserted into the hash table. |
*/ |
void hash_table_insert(hash_table_t *h, unsigned long key[], link_t *item) |
{ |
hash_index_t chain; |
assert(item); |
assert(h && h->op && h->op->hash && h->op->compare); |
chain = h->op->hash(key); |
assert(chain < h->entries); |
list_append(item, &h->entry[chain]); |
} |
/** Search hash table for an item matching keys. |
* |
* @param h Hash table. |
* @param key Array of all keys needed to compute hash index. |
* |
* @return Matching item on success, NULL if there is no such item. |
*/ |
link_t *hash_table_find(hash_table_t *h, unsigned long key[]) |
{ |
link_t *cur; |
hash_index_t chain; |
assert(h && h->op && h->op->hash && h->op->compare); |
chain = h->op->hash(key); |
assert(chain < h->entries); |
for (cur = h->entry[chain].next; cur != &h->entry[chain]; |
cur = cur->next) { |
if (h->op->compare(key, h->max_keys, cur)) { |
/* |
* The entry is there. |
*/ |
return cur; |
} |
} |
return NULL; |
} |
/** Remove all matching items from hash table. |
* |
* For each removed item, h->remove_callback() is called. |
* |
* @param h Hash table. |
* @param key Array of keys that will be compared against items of |
* the hash table. |
* @param keys Number of keys in the 'key' array. |
*/ |
void hash_table_remove(hash_table_t *h, unsigned long key[], hash_count_t keys) |
{ |
hash_index_t chain; |
link_t *cur; |
assert(h && h->op && h->op->hash && h->op->compare && |
h->op->remove_callback); |
assert(keys <= h->max_keys); |
if (keys == h->max_keys) { |
/* |
* All keys are known, hash_table_find() can be used to find the |
* entry. |
*/ |
cur = hash_table_find(h, key); |
if (cur) { |
list_remove(cur); |
h->op->remove_callback(cur); |
} |
return; |
} |
/* |
* Fewer keys were passed. |
* Any partially matching entries are to be removed. |
*/ |
for (chain = 0; chain < h->entries; chain++) { |
for (cur = h->entry[chain].next; cur != &h->entry[chain]; |
cur = cur->next) { |
if (h->op->compare(key, keys, cur)) { |
link_t *hlp; |
hlp = cur; |
cur = cur->prev; |
list_remove(hlp); |
h->op->remove_callback(hlp); |
continue; |
} |
} |
} |
} |
/** @} |
*/ |
/branches/tracing/uspace/lib/libc/generic/adt/list.c |
---|
0,0 → 1,112 |
/* |
* Copyright (c) 2004 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 libc |
* @{ |
*/ |
/** @file |
*/ |
#include <adt/list.h> |
/** Check for membership |
* |
* Check whether link is contained in the list head. |
* The membership is defined as pointer equivalence. |
* |
* @param link Item to look for. |
* @param head List to look in. |
* |
* @return true if link is contained in head, false otherwise. |
* |
*/ |
int list_member(const link_t *link, const link_t *head) |
{ |
int found = 0; |
link_t *hlp = head->next; |
while (hlp != head) { |
if (hlp == link) { |
found = 1; |
break; |
} |
hlp = hlp->next; |
} |
return found; |
} |
/** Concatenate two lists |
* |
* Concatenate lists head1 and head2, producing a single |
* list head1 containing items from both (in head1, head2 |
* order) and empty list head2. |
* |
* @param head1 First list and concatenated output |
* @param head2 Second list and empty output. |
* |
*/ |
void list_concat(link_t *head1, link_t *head2) |
{ |
if (list_empty(head2)) |
return; |
head2->next->prev = head1->prev; |
head2->prev->next = head1; |
head1->prev->next = head2->next; |
head1->prev = head2->prev; |
list_initialize(head2); |
} |
/** Count list items |
* |
* Return the number of items in the list. |
* |
* @param link List to count. |
* |
* @return Number of items in the list. |
* |
*/ |
unsigned int list_count(const link_t *link) |
{ |
unsigned int count = 0; |
link_t *hlp = link->next; |
while (hlp != link) { |
count++; |
hlp = hlp->next; |
} |
return count; |
} |
/** @} |
*/ |
/branches/tracing/uspace/lib/libc/generic/mman.c |
---|
37,17 → 37,18 |
#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); |
} |