/branches/network/uspace/lib/libfs/libfs.c |
---|
43,6 → 43,7 |
#include <assert.h> |
#include <dirent.h> |
#include <mem.h> |
#include <sys/stat.h> |
/** Register file system server. |
* |
69,7 → 70,7 |
* out-of-order, when it knows that the operation succeeded or failed. |
*/ |
ipc_call_t answer; |
aid_t req = async_send_0(vfs_phone, VFS_REGISTER, &answer); |
aid_t req = async_send_0(vfs_phone, VFS_IN_REGISTER, &answer); |
/* |
* Send our VFS info structure to VFS. |
104,7 → 105,7 |
} |
/* |
* Pick up the answer for the request to the VFS_REQUEST call. |
* Pick up the answer for the request to the VFS_IN_REQUEST call. |
*/ |
async_wait_for(req, NULL); |
reg->fs_handle = (int) IPC_GET_ARG1(answer); |
186,7 → 187,7 |
} |
ipc_call_t answer; |
aid_t msg = async_send_1(mountee_phone, VFS_MOUNTED, mr_dev_handle, |
aid_t msg = async_send_1(mountee_phone, VFS_OUT_MOUNTED, mr_dev_handle, |
&answer); |
ipc_forward_fast(callid, mountee_phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME); |
async_wait_for(msg, &rc); |
213,8 → 214,8 |
* file system implementation |
* @param fs_handle File system handle of the file system where to perform |
* the lookup. |
* @param rid Request ID of the VFS_LOOKUP request. |
* @param request VFS_LOOKUP request data itself. |
* @param rid Request ID of the VFS_OUT_LOOKUP request. |
* @param request VFS_OUT_LOOKUP request data itself. |
* |
*/ |
void libfs_lookup(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid, |
237,7 → 238,7 |
fs_node_t *tmp = NULL; |
if (cur->mp_data.mp_active) { |
ipc_forward_slow(rid, cur->mp_data.phone, VFS_LOOKUP, |
ipc_forward_slow(rid, cur->mp_data.phone, VFS_OUT_LOOKUP, |
next, last, cur->mp_data.dev_handle, lflag, index, |
IPC_FF_ROUTE_FROM_ME); |
ops->node_put(cur); |
272,9 → 273,9 |
else |
next--; |
ipc_forward_slow(rid, tmp->mp_data.phone, VFS_LOOKUP, |
next, last, tmp->mp_data.dev_handle, lflag, index, |
IPC_FF_ROUTE_FROM_ME); |
ipc_forward_slow(rid, tmp->mp_data.phone, |
VFS_OUT_LOOKUP, next, last, tmp->mp_data.dev_handle, |
lflag, index, IPC_FF_ROUTE_FROM_ME); |
ops->node_put(cur); |
ops->node_put(tmp); |
if (par) |
428,12 → 429,42 |
ops->node_put(tmp); |
} |
void libfs_stat(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid, |
ipc_call_t *request) |
{ |
dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request); |
fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request); |
fs_node_t *fn = ops->node_get(dev_handle, index); |
ipc_callid_t callid; |
size_t size; |
if (!ipc_data_read_receive(&callid, &size) || |
size != sizeof(struct stat)) { |
ipc_answer_0(callid, EINVAL); |
ipc_answer_0(rid, EINVAL); |
return; |
} |
struct stat stat; |
memset(&stat, 0, sizeof(struct stat)); |
stat.fs_handle = fs_handle; |
stat.dev_handle = dev_handle; |
stat.index = index; |
stat.lnkcnt = ops->lnkcnt_get(fn); |
stat.is_file = ops->is_file(fn); |
stat.size = ops->size_get(fn); |
ipc_data_read_finalize(callid, &stat, sizeof(struct stat)); |
ipc_answer_0(rid, EOK); |
} |
/** Open VFS triplet. |
* |
* @param ops libfs operations structure with function pointers to |
* file system implementation |
* @param rid Request ID of the VFS_OPEN_NODE request. |
* @param request VFS_OPEN_NODE request data itself. |
* @param rid Request ID of the VFS_OUT_OPEN_NODE request. |
* @param request VFS_OUT_OPEN_NODE request data itself. |
* |
*/ |
void libfs_open_node(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid, |
/branches/network/uspace/lib/libfs/libfs.h |
---|
84,6 → 84,7 |
extern void libfs_mount(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *); |
extern void libfs_lookup(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *); |
extern void libfs_stat(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *); |
extern void libfs_open_node(libfs_ops_t *, fs_handle_t, ipc_callid_t, |
ipc_call_t *); |
/branches/network/uspace/lib/libblock/libblock.c |
---|
63,6 → 63,7 |
fibril_mutex_t lock; |
size_t block_size; /**< Block size. */ |
unsigned block_count; /**< Total number of blocks. */ |
unsigned blocks_cached; /**< Number of cached blocks. */ |
hash_table_t block_hash; |
link_t free_head; |
enum cache_mode mode; |
72,6 → 73,7 |
link_t link; |
dev_handle_t dev_handle; |
int dev_phone; |
fibril_mutex_t com_area_lock; |
void *com_area; |
size_t com_size; |
void *bb_buf; |
80,8 → 82,8 |
cache_t *cache; |
} devcon_t; |
static int write_block(devcon_t *devcon, bn_t boff, size_t block_size, |
const void *src); |
static int read_block(devcon_t *devcon, bn_t boff, size_t block_size); |
static int write_block(devcon_t *devcon, bn_t boff, size_t block_size); |
static devcon_t *devcon_search(dev_handle_t dev_handle) |
{ |
112,6 → 114,7 |
link_initialize(&devcon->link); |
devcon->dev_handle = dev_handle; |
devcon->dev_phone = dev_phone; |
fibril_mutex_initialize(&devcon->com_area_lock); |
devcon->com_area = com_area; |
devcon->com_size = com_size; |
devcon->bb_buf = NULL; |
211,14 → 214,16 |
if (!bb_buf) |
return ENOMEM; |
off_t bufpos = 0; |
size_t buflen = 0; |
rc = block_read(dev_handle, &bufpos, &buflen, &off, |
bb_buf, size, size); |
fibril_mutex_lock(&devcon->com_area_lock); |
rc = read_block(devcon, 0, size); |
if (rc != EOK) { |
fibril_mutex_unlock(&devcon->com_area_lock); |
free(bb_buf); |
return rc; |
} |
memcpy(bb_buf, devcon->com_area, size); |
fibril_mutex_unlock(&devcon->com_area_lock); |
devcon->bb_buf = bb_buf; |
devcon->bb_off = off; |
devcon->bb_size = size; |
271,6 → 276,7 |
list_initialize(&cache->free_head); |
cache->block_size = size; |
cache->block_count = blocks; |
cache->blocks_cached = 0; |
cache->mode = mode; |
if (!hash_table_create(&cache->block_hash, CACHE_BUCKETS, 1, |
283,8 → 289,14 |
return EOK; |
} |
#define CACHE_LO_WATERMARK 10 |
#define CACHE_HI_WATERMARK 20 |
static bool cache_can_grow(cache_t *cache) |
{ |
if (cache->blocks_cached < CACHE_LO_WATERMARK) |
return true; |
if (!list_empty(&cache->free_head)) |
return false; |
return true; |
} |
315,6 → 327,7 |
block_t *b; |
link_t *l; |
unsigned long key = boff; |
bn_t oboff; |
devcon = devcon_search(dev_handle); |
339,9 → 352,6 |
* The block was not found in the cache. |
*/ |
int rc; |
off_t bufpos = 0; |
size_t buflen = 0; |
off_t pos = boff * cache->block_size; |
bool sync = false; |
if (cache_can_grow(cache)) { |
358,6 → 368,7 |
free(b); |
goto recycle; |
} |
cache->blocks_cached++; |
} else { |
/* |
* Try to recycle a block from the free list. |
367,8 → 378,9 |
assert(!list_empty(&cache->free_head)); |
l = cache->free_head.next; |
list_remove(l); |
b = hash_table_get_instance(l, block_t, hash_link); |
b = list_get_instance(l, block_t, free_link); |
sync = b->dirty; |
oboff = b->boff; |
temp_key = b->boff; |
hash_table_remove(&cache->block_hash, &temp_key, 1); |
} |
392,7 → 404,11 |
* The block is dirty and needs to be written back to |
* the device before we can read in the new contents. |
*/ |
abort(); /* TODO: block_write() */ |
fibril_mutex_lock(&devcon->com_area_lock); |
memcpy(devcon->com_area, b->data, b->size); |
rc = write_block(devcon, oboff, cache->block_size); |
assert(rc == EOK); |
fibril_mutex_unlock(&devcon->com_area_lock); |
} |
if (!(flags & BLOCK_FLAGS_NOREAD)) { |
/* |
399,9 → 415,11 |
* The block contains old or no data. We need to read |
* the new contents from the device. |
*/ |
rc = block_read(dev_handle, &bufpos, &buflen, &pos, |
b->data, cache->block_size, cache->block_size); |
fibril_mutex_lock(&devcon->com_area_lock); |
rc = read_block(devcon, b->boff, cache->block_size); |
assert(rc == EOK); |
memcpy(b->data, devcon->com_area, cache->block_size); |
fibril_mutex_unlock(&devcon->com_area_lock); |
} |
fibril_mutex_unlock(&b->lock); |
429,14 → 447,43 |
fibril_mutex_lock(&block->lock); |
if (!--block->refcnt) { |
/* |
* Last reference to the block was dropped, put the block on the |
* free list. |
* Last reference to the block was dropped. Either free the |
* block or put it on the free list. |
*/ |
if (cache->blocks_cached > CACHE_HI_WATERMARK) { |
/* |
* Currently there are too many cached blocks. |
*/ |
if (block->dirty) { |
fibril_mutex_lock(&devcon->com_area_lock); |
memcpy(devcon->com_area, block->data, |
block->size); |
rc = write_block(devcon, block->boff, |
block->size); |
assert(rc == EOK); |
fibril_mutex_unlock(&devcon->com_area_lock); |
} |
/* |
* Take the block out of the cache and free it. |
*/ |
unsigned long key = block->boff; |
hash_table_remove(&cache->block_hash, &key, 1); |
free(block); |
free(block->data); |
cache->blocks_cached--; |
fibril_mutex_unlock(&cache->lock); |
return; |
} |
/* |
* Put the block on the free list. |
*/ |
list_append(&block->free_link, &cache->free_head); |
if (cache->mode != CACHE_MODE_WB && block->dirty) { |
rc = write_block(devcon, block->boff, block->size, |
block->data); |
fibril_mutex_lock(&devcon->com_area_lock); |
memcpy(devcon->com_area, block->data, block->size); |
rc = write_block(devcon, block->boff, block->size); |
assert(rc == EOK); |
fibril_mutex_unlock(&devcon->com_area_lock); |
block->dirty = false; |
} |
445,7 → 492,7 |
fibril_mutex_unlock(&cache->lock); |
} |
/** Read data from a block device. |
/** Read sequential data from a block device. |
* |
* @param dev_handle Device handle of the block device. |
* @param bufpos Pointer to the first unread valid offset within the |
459,9 → 506,8 |
* |
* @return EOK on success or a negative return code on failure. |
*/ |
int |
block_read(dev_handle_t dev_handle, off_t *bufpos, size_t *buflen, off_t *pos, |
void *dst, size_t size, size_t block_size) |
int block_seqread(dev_handle_t dev_handle, off_t *bufpos, size_t *buflen, |
off_t *pos, void *dst, size_t size, size_t block_size) |
{ |
off_t offset = 0; |
size_t left = size; |
468,6 → 514,7 |
devcon_t *devcon = devcon_search(dev_handle); |
assert(devcon); |
fibril_mutex_lock(&devcon->com_area_lock); |
while (left > 0) { |
size_t rd; |
490,20 → 537,46 |
if (*bufpos == (off_t) *buflen) { |
/* Refill the communication buffer with a new block. */ |
ipcarg_t retval; |
int rc = async_req_2_1(devcon->dev_phone, BD_READ_BLOCK, |
*pos / block_size, block_size, &retval); |
if ((rc != EOK) || (retval != EOK)) |
return (rc != EOK ? rc : (int) retval); |
int rc; |
rc = read_block(devcon, *pos / block_size, block_size); |
if (rc != EOK) { |
fibril_mutex_unlock(&devcon->com_area_lock); |
return rc; |
} |
*bufpos = 0; |
*buflen = block_size; |
} |
} |
fibril_mutex_unlock(&devcon->com_area_lock); |
return EOK; |
} |
/** Read block from block device. |
* |
* @param devcon Device connection. |
* @param boff Block index. |
* @param block_size Block size. |
* @param src Buffer for storing the data. |
* |
* @return EOK on success or negative error code on failure. |
*/ |
static int read_block(devcon_t *devcon, bn_t boff, size_t block_size) |
{ |
ipcarg_t retval; |
int rc; |
assert(devcon); |
rc = async_req_2_1(devcon->dev_phone, BD_READ_BLOCK, boff, block_size, |
&retval); |
if ((rc != EOK) || (retval != EOK)) |
return (rc != EOK ? rc : (int) retval); |
return EOK; |
} |
/** Write block to block device. |
* |
* @param devcon Device connection. |
513,17 → 586,14 |
* |
* @return EOK on success or negative error code on failure. |
*/ |
static int write_block(devcon_t *devcon, bn_t boff, size_t block_size, |
const void *src) |
static int write_block(devcon_t *devcon, bn_t boff, size_t block_size) |
{ |
ipcarg_t retval; |
int rc; |
assert(devcon); |
memcpy(devcon->com_area, src, block_size); |
rc = async_req_2_1(devcon->dev_phone, BD_WRITE_BLOCK, |
boff, block_size, &retval); |
rc = async_req_2_1(devcon->dev_phone, BD_WRITE_BLOCK, boff, block_size, |
&retval); |
if ((rc != EOK) || (retval != EOK)) |
return (rc != EOK ? rc : (int) retval); |
/branches/network/uspace/lib/libblock/libblock.h |
---|
100,11 → 100,11 |
extern int block_cache_init(dev_handle_t, size_t, unsigned, enum cache_mode); |
extern block_t *block_get(dev_handle_t, bn_t, int flags); |
extern block_t *block_get(dev_handle_t, bn_t, int); |
extern void block_put(block_t *); |
extern int block_read(dev_handle_t, off_t *, size_t *, off_t *, void *, size_t, |
size_t); |
extern int block_seqread(dev_handle_t, off_t *, size_t *, off_t *, void *, |
size_t, size_t); |
#endif |
/branches/network/uspace/lib/libc/malloc/malloc.c |
---|
File deleted |
/branches/network/uspace/lib/libc/include/getopt.h |
---|
58,7 → 58,7 |
}; |
/* HelenOS Port - These need to be exposed for legacy getopt() */ |
extern char *optarg; |
extern const char *optarg; |
extern int optind, opterr, optopt; |
extern int optreset; |
/branches/network/uspace/lib/libc/include/string.h |
---|
74,8 → 74,8 |
extern void wstr_nstr(char *dst, const wchar_t *src, size_t size); |
extern const char *str_chr(const char *str, wchar_t ch); |
extern const char *str_rchr(const char *str, wchar_t ch); |
extern char *str_chr(const char *str, wchar_t ch); |
extern char *str_rchr(const char *str, wchar_t ch); |
extern bool wstr_linsert(wchar_t *str, wchar_t ch, size_t pos, size_t max_pos); |
extern bool wstr_remove(wchar_t *str, size_t pos); |
/branches/network/uspace/lib/libc/include/malloc.h |
---|
1,537 → 1,51 |
/* |
Default header file for malloc-2.8.x, written by Doug Lea |
and released to the public domain, as explained at |
http://creativecommons.org/licenses/publicdomain. |
last update: Mon Aug 15 08:55:52 2005 Doug Lea (dl at gee) |
* 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. |
*/ |
This header is for ANSI C/C++ only. You can set any of |
the following #defines before including: |
* If USE_DL_PREFIX is defined, it is assumed that malloc.c |
was also compiled with this option, so all routines |
have names starting with "dl". |
* If HAVE_USR_INCLUDE_MALLOC_H is defined, it is assumed that this |
file will be #included AFTER <malloc.h>. This is needed only if |
your system defines a struct mallinfo that is incompatible with the |
standard one declared here. Otherwise, you can include this file |
INSTEAD of your system system <malloc.h>. At least on ANSI, all |
declarations should be compatible with system versions |
* If MSPACES is defined, declarations for mspace versions are included. |
*/ |
#ifndef MALLOC_280_H |
#define MALLOC_280_H |
#ifdef __cplusplus |
extern "C" { |
#endif |
#include <stddef.h> /* for size_t */ |
#if !ONLY_MSPACES |
#ifndef USE_DL_PREFIX |
#define dlcalloc calloc |
#define dlfree free |
#define dlmalloc malloc |
#define dlmemalign memalign |
#define dlrealloc realloc |
#define dlvalloc valloc |
#define dlpvalloc pvalloc |
#define dlmallinfo mallinfo |
#define dlmallopt mallopt |
#define dlmalloc_trim malloc_trim |
#define dlmalloc_stats malloc_stats |
#define dlmalloc_usable_size malloc_usable_size |
#define dlmalloc_footprint malloc_footprint |
#define dlmalloc_max_footprint malloc_max_footprint |
#define dlindependent_calloc independent_calloc |
#define dlindependent_comalloc independent_comalloc |
#endif /* USE_DL_PREFIX */ |
/* |
malloc(size_t n) |
Returns a pointer to a newly allocated chunk of at least n bytes, or |
null if no space is available, in which case errno is set to ENOMEM |
on ANSI C systems. |
If n is zero, malloc returns a minimum-sized chunk. (The minimum |
size is 16 bytes on most 32bit systems, and 32 bytes on 64bit |
systems.) Note that size_t is an unsigned type, so calls with |
arguments that would be negative if signed are interpreted as |
requests for huge amounts of space, which will often fail. The |
maximum supported value of n differs across systems, but is in all |
cases less than the maximum representable value of a size_t. |
*/ |
void* dlmalloc(size_t); |
/* |
free(void* p) |
Releases the chunk of memory pointed to by p, that had been previously |
allocated using malloc or a related routine such as realloc. |
It has no effect if p is null. If p was not malloced or already |
freed, free(p) will by default cuase the current program to abort. |
*/ |
void dlfree(void*); |
/* |
calloc(size_t n_elements, size_t element_size); |
Returns a pointer to n_elements * element_size bytes, with all locations |
set to zero. |
*/ |
void* dlcalloc(size_t, size_t); |
/* |
realloc(void* p, size_t n) |
Returns a pointer to a chunk of size n that contains the same data |
as does chunk p up to the minimum of (n, p's size) bytes, or null |
if no space is available. |
The returned pointer may or may not be the same as p. The algorithm |
prefers extending p in most cases when possible, otherwise it |
employs the equivalent of a malloc-copy-free sequence. |
If p is null, realloc is equivalent to malloc. |
If space is not available, realloc returns null, errno is set (if on |
ANSI) and p is NOT freed. |
if n is for fewer bytes than already held by p, the newly unused |
space is lopped off and freed if possible. realloc with a size |
argument of zero (re)allocates a minimum-sized chunk. |
The old unix realloc convention of allowing the last-free'd chunk |
to be used as an argument to realloc is not supported. |
*/ |
void* dlrealloc(void*, size_t); |
/* |
memalign(size_t alignment, size_t n); |
Returns a pointer to a newly allocated chunk of n bytes, aligned |
in accord with the alignment argument. |
The alignment argument should be a power of two. If the argument is |
not a power of two, the nearest greater power is used. |
8-byte alignment is guaranteed by normal malloc calls, so don't |
bother calling memalign with an argument of 8 or less. |
Overreliance on memalign is a sure way to fragment space. |
*/ |
void* dlmemalign(size_t, size_t); |
/* |
valloc(size_t n); |
Equivalent to memalign(pagesize, n), where pagesize is the page |
size of the system. If the pagesize is unknown, 4096 is used. |
*/ |
void* dlvalloc(size_t); |
/* |
mallopt(int parameter_number, int parameter_value) |
Sets tunable parameters The format is to provide a |
(parameter-number, parameter-value) pair. mallopt then sets the |
corresponding parameter to the argument value if it can (i.e., so |
long as the value is meaningful), and returns 1 if successful else |
0. SVID/XPG/ANSI defines four standard param numbers for mallopt, |
normally defined in malloc.h. None of these are use in this malloc, |
so setting them has no effect. But this malloc also supports other |
options in mallopt: |
Symbol param # default allowed param values |
M_TRIM_THRESHOLD -1 2*1024*1024 any (-1U disables trimming) |
M_GRANULARITY -2 page size any power of 2 >= page size |
M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support) |
*/ |
int dlmallopt(int, int); |
#define M_TRIM_THRESHOLD (-1) |
#define M_GRANULARITY (-2) |
#define M_MMAP_THRESHOLD (-3) |
/* |
malloc_footprint(); |
Returns the number of bytes obtained from the system. The total |
number of bytes allocated by malloc, realloc etc., is less than this |
value. Unlike mallinfo, this function returns only a precomputed |
result, so can be called frequently to monitor memory consumption. |
Even if locks are otherwise defined, this function does not use them, |
so results might not be up to date. |
*/ |
size_t dlmalloc_footprint(void); |
size_t dlmalloc_max_footprint(void); |
#if !NO_MALLINFO |
/* |
mallinfo() |
Returns (by copy) a struct containing various summary statistics: |
arena: current total non-mmapped bytes allocated from system |
ordblks: the number of free chunks |
smblks: always zero. |
hblks: current number of mmapped regions |
hblkhd: total bytes held in mmapped regions |
usmblks: the maximum total allocated space. This will be greater |
than current total if trimming has occurred. |
fsmblks: always zero |
uordblks: current total allocated space (normal or mmapped) |
fordblks: total free space |
keepcost: the maximum number of bytes that could ideally be released |
back to system via malloc_trim. ("ideally" means that |
it ignores page restrictions etc.) |
Because these fields are ints, but internal bookkeeping may |
be kept as longs, the reported values may wrap around zero and |
thus be inaccurate. |
*/ |
#ifndef HAVE_USR_INCLUDE_MALLOC_H |
#ifndef _MALLOC_H |
#ifndef MALLINFO_FIELD_TYPE |
#define MALLINFO_FIELD_TYPE size_t |
#endif /* MALLINFO_FIELD_TYPE */ |
struct mallinfo { |
MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */ |
MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */ |
MALLINFO_FIELD_TYPE smblks; /* always 0 */ |
MALLINFO_FIELD_TYPE hblks; /* always 0 */ |
MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */ |
MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */ |
MALLINFO_FIELD_TYPE fsmblks; /* always 0 */ |
MALLINFO_FIELD_TYPE uordblks; /* total allocated space */ |
MALLINFO_FIELD_TYPE fordblks; /* total free space */ |
MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */ |
}; |
#endif /* _MALLOC_H */ |
#endif /* HAVE_USR_INCLUDE_MALLOC_H */ |
struct mallinfo dlmallinfo(void); |
#endif /* NO_MALLINFO */ |
/* |
independent_calloc(size_t n_elements, size_t element_size, void* chunks[]); |
independent_calloc is similar to calloc, but instead of returning a |
single cleared space, it returns an array of pointers to n_elements |
independent elements that can hold contents of size elem_size, each |
of which starts out cleared, and can be independently freed, |
realloc'ed etc. The elements are guaranteed to be adjacently |
allocated (this is not guaranteed to occur with multiple callocs or |
mallocs), which may also improve cache locality in some |
applications. |
The "chunks" argument is optional (i.e., may be null, which is |
probably the most typical usage). If it is null, the returned array |
is itself dynamically allocated and should also be freed when it is |
no longer needed. Otherwise, the chunks array must be of at least |
n_elements in length. It is filled in with the pointers to the |
chunks. |
In either case, independent_calloc returns this pointer array, or |
null if the allocation failed. If n_elements is zero and "chunks" |
is null, it returns a chunk representing an array with zero elements |
(which should be freed if not wanted). |
Each element must be individually freed when it is no longer |
needed. If you'd like to instead be able to free all at once, you |
should instead use regular calloc and assign pointers into this |
space to represent elements. (In this case though, you cannot |
independently free elements.) |
independent_calloc simplifies and speeds up implementations of many |
kinds of pools. It may also be useful when constructing large data |
structures that initially have a fixed number of fixed-sized nodes, |
but the number is not known at compile time, and some of the nodes |
may later need to be freed. For example: |
struct Node { int item; struct Node* next; }; |
struct Node* build_list() { |
struct Node** pool; |
int n = read_number_of_nodes_needed(); |
if (n <= 0) return 0; |
pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0); |
if (pool == 0) die(); |
// organize into a linked list... |
struct Node* first = pool[0]; |
for (i = 0; i < n-1; ++i) |
pool[i]->next = pool[i+1]; |
free(pool); // Can now free the array (or not, if it is needed later) |
return first; |
} |
*/ |
void** dlindependent_calloc(size_t, size_t, void**); |
/* |
independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]); |
independent_comalloc allocates, all at once, a set of n_elements |
chunks with sizes indicated in the "sizes" array. It returns |
an array of pointers to these elements, each of which can be |
independently freed, realloc'ed etc. The elements are guaranteed to |
be adjacently allocated (this is not guaranteed to occur with |
multiple callocs or mallocs), which may also improve cache locality |
in some applications. |
The "chunks" argument is optional (i.e., may be null). If it is null |
the returned array is itself dynamically allocated and should also |
be freed when it is no longer needed. Otherwise, the chunks array |
must be of at least n_elements in length. It is filled in with the |
pointers to the chunks. |
In either case, independent_comalloc returns this pointer array, or |
null if the allocation failed. If n_elements is zero and chunks is |
null, it returns a chunk representing an array with zero elements |
(which should be freed if not wanted). |
Each element must be individually freed when it is no longer |
needed. If you'd like to instead be able to free all at once, you |
should instead use a single regular malloc, and assign pointers at |
particular offsets in the aggregate space. (In this case though, you |
cannot independently free elements.) |
independent_comallac differs from independent_calloc in that each |
element may have a different size, and also that it does not |
automatically clear elements. |
independent_comalloc can be used to speed up allocation in cases |
where several structs or objects must always be allocated at the |
same time. For example: |
struct Head { ... } |
struct Foot { ... } |
void send_message(char* msg) { |
int msglen = strlen(msg); |
size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) }; |
void* chunks[3]; |
if (independent_comalloc(3, sizes, chunks) == 0) |
die(); |
struct Head* head = (struct Head*)(chunks[0]); |
char* body = (char*)(chunks[1]); |
struct Foot* foot = (struct Foot*)(chunks[2]); |
// ... |
} |
In general though, independent_comalloc is worth using only for |
larger values of n_elements. For small values, you probably won't |
detect enough difference from series of malloc calls to bother. |
Overuse of independent_comalloc can increase overall memory usage, |
since it cannot reuse existing noncontiguous small chunks that |
might be available for some of the elements. |
*/ |
void** dlindependent_comalloc(size_t, size_t*, void**); |
/* |
pvalloc(size_t n); |
Equivalent to valloc(minimum-page-that-holds(n)), that is, |
round up n to nearest pagesize. |
/** @addtogroup libc |
* @{ |
*/ |
void* dlpvalloc(size_t); |
/** @file |
*/ |
/* |
malloc_trim(size_t pad); |
#ifndef LIBC_MALLOC_H_ |
#define LIBC_MALLOC_H_ |
If possible, gives memory back to the system (via negative arguments |
to sbrk) if there is unused memory at the `high' end of the malloc |
pool or in unused MMAP segments. You can call this after freeing |
large blocks of memory to potentially reduce the system-level memory |
requirements of a program. However, it cannot guarantee to reduce |
memory. Under some allocation patterns, some large free blocks of |
memory will be locked between two used chunks, so they cannot be |
given back to the system. |
#include <sys/types.h> |
The `pad' argument to malloc_trim represents the amount of free |
trailing space to leave untrimmed. If this argument is zero, only |
the minimum amount of memory to maintain internal data structures |
will be left. Non-zero arguments can be supplied to maintain enough |
trailing space to service future expected allocations without having |
to re-obtain memory from the system. |
extern void __heap_init(void); |
extern uintptr_t get_max_heap_addr(void); |
Malloc_trim returns 1 if it actually released any memory, else 0. |
*/ |
int dlmalloc_trim(size_t); |
extern void *malloc(const size_t size); |
extern void *memalign(const size_t align, const size_t size); |
extern void *realloc(const void *addr, const size_t size); |
extern void free(const void *addr); |
/* |
malloc_usable_size(void* p); |
Returns the number of bytes you can actually use in |
an allocated chunk, which may be more than you requested (although |
often not) due to alignment and minimum size constraints. |
You can use this many bytes without worrying about |
overwriting other allocated objects. This is not a particularly great |
programming practice. malloc_usable_size can be more useful in |
debugging and assertions, for example: |
p = malloc(n); |
assert(malloc_usable_size(p) >= 256); |
*/ |
size_t dlmalloc_usable_size(void*); |
/* |
malloc_stats(); |
Prints on stderr the amount of space obtained from the system (both |
via sbrk and mmap), the maximum amount (which may be more than |
current if malloc_trim and/or munmap got called), and the current |
number of bytes allocated via malloc (or realloc, etc) but not yet |
freed. Note that this is the number of bytes allocated, not the |
number requested. It will be larger than the number requested |
because of alignment and bookkeeping overhead. Because it includes |
alignment wastage as being in use, this figure may be greater than |
zero even when no user-level chunks are allocated. |
The reported current and maximum system memory can be inaccurate if |
a program makes other calls to system memory allocation functions |
(normally sbrk) outside of malloc. |
malloc_stats prints only the most commonly interesting statistics. |
More information can be obtained by calling mallinfo. |
*/ |
void dlmalloc_stats(void); |
#endif /* !ONLY_MSPACES */ |
#if MSPACES |
/* |
mspace is an opaque type representing an independent |
region of space that supports mspace_malloc, etc. |
*/ |
typedef void* mspace; |
/* |
create_mspace creates and returns a new independent space with the |
given initial capacity, or, if 0, the default granularity size. It |
returns null if there is no system memory available to create the |
space. If argument locked is non-zero, the space uses a separate |
lock to control access. The capacity of the space will grow |
dynamically as needed to service mspace_malloc requests. You can |
control the sizes of incremental increases of this space by |
compiling with a different DEFAULT_GRANULARITY or dynamically |
setting with mallopt(M_GRANULARITY, value). |
*/ |
mspace create_mspace(size_t capacity, int locked); |
/* |
destroy_mspace destroys the given space, and attempts to return all |
of its memory back to the system, returning the total number of |
bytes freed. After destruction, the results of access to all memory |
used by the space become undefined. |
*/ |
size_t destroy_mspace(mspace msp); |
/* |
create_mspace_with_base uses the memory supplied as the initial base |
of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this |
space is used for bookkeeping, so the capacity must be at least this |
large. (Otherwise 0 is returned.) When this initial space is |
exhausted, additional memory will be obtained from the system. |
Destroying this space will deallocate all additionally allocated |
space (if possible) but not the initial base. |
*/ |
mspace create_mspace_with_base(void* base, size_t capacity, int locked); |
/* |
mspace_malloc behaves as malloc, but operates within |
the given space. |
*/ |
void* mspace_malloc(mspace msp, size_t bytes); |
/* |
mspace_free behaves as free, but operates within |
the given space. |
If compiled with FOOTERS==1, mspace_free is not actually needed. |
free may be called instead of mspace_free because freed chunks from |
any space are handled by their originating spaces. |
*/ |
void mspace_free(mspace msp, void* mem); |
/* |
mspace_realloc behaves as realloc, but operates within |
the given space. |
If compiled with FOOTERS==1, mspace_realloc is not actually |
needed. realloc may be called instead of mspace_realloc because |
realloced chunks from any space are handled by their originating |
spaces. |
*/ |
void* mspace_realloc(mspace msp, void* mem, size_t newsize); |
/* |
mspace_calloc behaves as calloc, but operates within |
the given space. |
*/ |
void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size); |
/* |
mspace_memalign behaves as memalign, but operates within |
the given space. |
*/ |
void* mspace_memalign(mspace msp, size_t alignment, size_t bytes); |
/* |
mspace_independent_calloc behaves as independent_calloc, but |
operates within the given space. |
*/ |
void** mspace_independent_calloc(mspace msp, size_t n_elements, |
size_t elem_size, void* chunks[]); |
/* |
mspace_independent_comalloc behaves as independent_comalloc, but |
operates within the given space. |
*/ |
void** mspace_independent_comalloc(mspace msp, size_t n_elements, |
size_t sizes[], void* chunks[]); |
/* |
mspace_footprint() returns the number of bytes obtained from the |
system for this space. |
*/ |
size_t mspace_footprint(mspace msp); |
#if !NO_MALLINFO |
/* |
mspace_mallinfo behaves as mallinfo, but reports properties of |
the given space. |
*/ |
struct mallinfo mspace_mallinfo(mspace msp); |
#endif /* NO_MALLINFO */ |
/* |
mspace_malloc_stats behaves as malloc_stats, but reports |
properties of the given space. |
*/ |
void mspace_malloc_stats(mspace msp); |
/* |
mspace_trim behaves as malloc_trim, but |
operates within the given space. |
*/ |
int mspace_trim(mspace msp, size_t pad); |
/* |
An alias for mallopt. |
*/ |
int mspace_mallopt(int, int); |
#endif /* MSPACES */ |
#ifdef __cplusplus |
}; /* end of extern "C" */ |
#endif |
#endif /* MALLOC_280_H */ |
/** @} |
/** @} |
*/ |
/branches/network/uspace/lib/libc/include/vfs/vfs.h |
---|
55,8 → 55,8 |
extern int mount(const char *, const char *, const char *, const char *, |
unsigned int); |
extern void stdio_init(int filc, fdi_node_t *filv[]); |
extern void stdio_done(void); |
extern void __stdio_init(int filc, fdi_node_t *filv[]); |
extern void __stdio_done(void); |
extern int open_node(fdi_node_t *, int); |
extern int fd_phone(int); |
/branches/network/uspace/lib/libc/include/async.h |
---|
46,11 → 46,7 |
extern atomic_t async_futex; |
static inline void async_manager(void) |
{ |
fibril_switch(FIBRIL_TO_MANAGER); |
} |
extern int __async_init(void); |
extern ipc_callid_t async_get_call_timeout(ipc_call_t *call, suseconds_t usecs); |
static inline ipc_callid_t async_get_call(ipc_call_t *data) |
58,6 → 54,11 |
return async_get_call_timeout(data, 0); |
} |
static inline void async_manager(void) |
{ |
fibril_switch(FIBRIL_TO_MANAGER); |
} |
/* |
* User-friendly wrappers for async_send_fast() and async_send_slow(). The |
* macros are in the form async_send_m(), where m denotes the number of payload |
94,7 → 95,6 |
extern void async_usleep(suseconds_t timeout); |
extern void async_create_manager(void); |
extern void async_destroy_manager(void); |
extern int _async_init(void); |
extern void async_set_client_connection(async_client_conn_t conn); |
extern void async_set_interrupt_received(async_client_conn_t conn); |
/branches/network/uspace/lib/libc/include/stdlib.h |
---|
38,10 → 38,10 |
#include <unistd.h> |
#include <malloc.h> |
#define abort() _exit(1) |
#define exit(status) _exit((status)) |
#define abort() _exit(1) |
#define exit(status) _exit((status)) |
#define RAND_MAX 714025 |
#define RAND_MAX 714025 |
extern long int random(void); |
extern void srandom(unsigned int seed); |
50,6 → 50,7 |
{ |
return random(); |
} |
static inline void srand(unsigned int seed) |
{ |
srandom(seed); |
/branches/network/uspace/lib/libc/include/stdio.h |
---|
37,20 → 37,21 |
#include <sys/types.h> |
#include <stdarg.h> |
#include <string.h> |
#include <adt/list.h> |
#define EOF (-1) |
/** Default size for stream I/O buffers */ |
#define BUFSIZ 4096 |
#define BUFSIZ 4096 |
#define DEBUG(fmt, ...) \ |
{ \ |
char buf[256]; \ |
int n = snprintf(buf, sizeof(buf), fmt, ##__VA_ARGS__); \ |
if (n > 0) \ |
(void) __SYSCALL3(SYS_KLOG, 1, (sysarg_t) buf, str_size(buf)); \ |
} |
{ \ |
char _buf[256]; \ |
int _n = snprintf(_buf, sizeof(_buf), fmt, ##__VA_ARGS__); \ |
if (_n > 0) \ |
(void) __SYSCALL3(SYS_KLOG, 1, (sysarg_t) _buf, str_size(_buf)); \ |
} |
#ifndef SEEK_SET |
#define SEEK_SET 0 |
/branches/network/uspace/lib/libc/include/bitops.h |
---|
26,7 → 26,7 |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup generic |
/** @addtogroup generic |
* @{ |
*/ |
/** @file |
42,10 → 42,10 |
* |
* If number is zero, it returns 0 |
*/ |
static inline int fnzb32(uint32_t arg) |
static inline unsigned int fnzb32(uint32_t arg) |
{ |
int n = 0; |
unsigned int n = 0; |
if (arg >> 16) { |
arg >>= 16; |
n += 16; |
74,19 → 74,22 |
return n; |
} |
static inline int fnzb64(uint64_t arg) |
static inline unsigned int fnzb64(uint64_t arg) |
{ |
int n = 0; |
unsigned int n = 0; |
if (arg >> 32) { |
arg >>= 32; |
n += 32; |
} |
return n + fnzb32((uint32_t) arg); |
return (n + fnzb32((uint32_t) arg)); |
} |
#define fnzb(x) fnzb32(x) |
static inline unsigned int fnzb(size_t arg) |
{ |
return fnzb64(arg); |
} |
#endif |
/branches/network/uspace/lib/libc/include/task.h |
---|
39,11 → 39,18 |
typedef uint64_t task_id_t; |
typedef enum { |
TASK_EXIT_NORMAL, |
TASK_EXIT_UNEXPECTED |
} task_exit_t; |
extern task_id_t task_get_id(void); |
extern int task_set_name(const char *name); |
extern task_id_t task_spawn(const char *path, char *const argv[]); |
extern int task_wait(task_id_t id); |
extern int task_wait(task_id_t id, task_exit_t *texit, int *retval); |
extern int task_retval(int val); |
#endif |
/** @} |
/branches/network/uspace/lib/libc/include/unistd.h |
---|
65,7 → 65,6 |
extern int chdir(const char *); |
extern void _exit(int status) __attribute__ ((noreturn)); |
extern void *sbrk(ssize_t incr); |
extern int usleep(unsigned long usec); |
extern unsigned int sleep(unsigned int seconds); |
/branches/network/uspace/lib/libc/include/fibril.h |
---|
75,7 → 75,7 |
/** Fibril-local variable specifier */ |
#define fibril_local __thread |
extern int context_save(context_t *c); |
extern int context_save(context_t *c) __attribute__ ((returns_twice)); |
extern void context_restore(context_t *c) __attribute__ ((noreturn)); |
extern fid_t fibril_create(int (*func)(void *), void *arg); |
/branches/network/uspace/lib/libc/include/devmap.h |
---|
47,6 → 47,9 |
extern int devmap_device_get_handle(const char *, dev_handle_t *, unsigned int); |
extern int devmap_device_connect(dev_handle_t, unsigned int); |
extern int devmap_null_create(void); |
extern void devmap_null_destroy(int); |
extern ipcarg_t devmap_device_get_count(void); |
extern ipcarg_t devmap_device_get_devices(ipcarg_t, dev_desc_t *); |
/branches/network/uspace/lib/libc/include/mem.h |
---|
39,9 → 39,9 |
#define bzero(ptr, len) memset((ptr), 0, (len)) |
extern void * memset(void *, int, size_t); |
extern void * memcpy(void *, const void *, size_t); |
extern void * memmove(void *, const void *, size_t); |
extern void *memset(void *, int, size_t); |
extern void *memcpy(void *, const void *, size_t); |
extern void *memmove(void *, const void *, size_t); |
extern int bcmp(const char *, const char *, size_t); |
/branches/network/uspace/lib/libc/include/io/console.h |
---|
43,6 → 43,13 |
KEY_RELEASE |
} console_ev_type_t; |
enum { |
CONSOLE_CCAP_NONE = 0, |
CONSOLE_CCAP_STYLE, |
CONSOLE_CCAP_INDEXED, |
CONSOLE_CCAP_RGB |
}; |
/** Console event structure. */ |
typedef struct { |
/** Press or release event. */ |
68,6 → 75,7 |
extern void console_set_rgb_color(int phone, int fg_color, int bg_color); |
extern void console_cursor_visibility(int phone, bool show); |
extern int console_get_color_cap(int phone, int *ccap); |
extern void console_kcon_enable(int phone); |
extern bool console_get_event(int phone, console_event_t *event); |
/branches/network/uspace/lib/libc/include/adt/gcdlcm.h |
---|
0,0 → 1,73 |
/* |
* 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 |
*/ |
#ifndef LIBC_GCDLCM_H_ |
#define LIBC_GCDLCM_H_ |
#include <sys/types.h> |
#define DECLARE_GCD(type, name) \ |
static inline type name(type a, type b) \ |
{ \ |
if (a == 0) \ |
return b; \ |
\ |
while (b != 0) { \ |
if (a > b) \ |
a -= b; \ |
else \ |
b -= a; \ |
} \ |
\ |
return a; \ |
} |
#define DECLARE_LCM(type, name, gcd) \ |
static inline type name(type a, type b) \ |
{ \ |
return (a * b) / gcd(a, b); \ |
} |
DECLARE_GCD(uint32_t, gcd32); |
DECLARE_GCD(uint64_t, gcd64); |
DECLARE_GCD(size_t, gcd); |
DECLARE_LCM(uint32_t, lcm32, gcd32); |
DECLARE_LCM(uint64_t, lcm64, gcd64); |
DECLARE_LCM(size_t, lcm, gcd); |
#endif |
/** @} |
*/ |
/branches/network/uspace/lib/libc/include/macros.h |
---|
35,6 → 35,9 |
#ifndef LIBC_MACROS_H_ |
#define LIBC_MACROS_H_ |
#define min(a, b) ((a) < (b) ? (a) : (b)) |
#define max(a, b) ((a) > (b) ? (a) : (b)) |
#define SIZE2KB(size) ((size) >> 10) |
#define SIZE2MB(size) ((size) >> 20) |
/branches/network/uspace/lib/libc/include/ipc/devmap.h |
---|
28,7 → 28,7 |
/** @addtogroup devmap |
* @{ |
*/ |
*/ |
#ifndef DEVMAP_DEVMAP_H_ |
#define DEVMAP_DEVMAP_H_ |
48,6 → 48,8 |
DEVMAP_DEVICE_UNREGISTER, |
DEVMAP_DEVICE_GET_NAME, |
DEVMAP_DEVICE_GET_HANDLE, |
DEVMAP_DEVICE_NULL_CREATE, |
DEVMAP_DEVICE_NULL_DESTROY, |
DEVMAP_DEVICE_GET_COUNT, |
DEVMAP_DEVICE_GET_DEVICES |
} devmap_request_t; |
/branches/network/uspace/lib/libc/include/ipc/vfs.h |
---|
57,36 → 57,40 |
} vfs_info_t; |
typedef enum { |
VFS_OPEN_NODE = IPC_FIRST_USER_METHOD, |
VFS_READ, |
VFS_WRITE, |
VFS_TRUNCATE, |
VFS_MOUNT, |
VFS_UNMOUNT, |
VFS_DEVICE, |
VFS_SYNC, |
VFS_CLOSE, |
VFS_LAST_CMN /* keep this the last member of this enum */ |
} vfs_request_cmn_t; |
VFS_IN_OPEN = IPC_FIRST_USER_METHOD, |
VFS_IN_OPEN_NODE, |
VFS_IN_READ, |
VFS_IN_WRITE, |
VFS_IN_SEEK, |
VFS_IN_TRUNCATE, |
VFS_IN_FSTAT, |
VFS_IN_CLOSE, |
VFS_IN_MOUNT, |
VFS_IN_UNMOUNT, |
VFS_IN_SYNC, |
VFS_IN_REGISTER, |
VFS_IN_MKDIR, |
VFS_IN_UNLINK, |
VFS_IN_RENAME, |
VFS_IN_STAT |
} vfs_in_request_t; |
typedef enum { |
VFS_LOOKUP = VFS_LAST_CMN, |
VFS_MOUNTED, |
VFS_DESTROY, |
VFS_LAST_CLNT /* keep this the last member of this enum */ |
} vfs_request_clnt_t; |
VFS_OUT_OPEN_NODE = IPC_FIRST_USER_METHOD, |
VFS_OUT_READ, |
VFS_OUT_WRITE, |
VFS_OUT_TRUNCATE, |
VFS_OUT_CLOSE, |
VFS_OUT_MOUNT, |
VFS_OUT_MOUNTED, |
VFS_OUT_UNMOUNT, |
VFS_OUT_SYNC, |
VFS_OUT_STAT, |
VFS_OUT_LOOKUP, |
VFS_OUT_DESTROY, |
VFS_OUT_LAST |
} vfs_out_request_t; |
typedef enum { |
VFS_REGISTER = VFS_LAST_CMN, |
VFS_OPEN, |
VFS_SEEK, |
VFS_MKDIR, |
VFS_UNLINK, |
VFS_RENAME, |
VFS_NODE, |
VFS_LAST_SRV /* keep this the last member of this enum */ |
} vfs_request_srv_t; |
/* |
* Lookup flags. |
*/ |
/branches/network/uspace/lib/libc/include/ipc/ns.h |
---|
39,7 → 39,9 |
typedef enum { |
NS_PING = IPC_FIRST_USER_METHOD, |
NS_TASK_WAIT |
NS_TASK_WAIT, |
NS_ID_INTRO, |
NS_RETVAL |
} ns_request_t; |
#endif |
/branches/network/uspace/lib/libc/include/ipc/console.h |
---|
39,7 → 39,8 |
#include <ipc/vfs.h> |
typedef enum { |
CONSOLE_GET_SIZE = VFS_LAST_SRV, |
CONSOLE_GET_SIZE = VFS_OUT_LAST, |
CONSOLE_GET_COLOR_CAP, |
CONSOLE_GET_EVENT, |
CONSOLE_GOTO, |
CONSOLE_CLEAR, |
/branches/network/uspace/lib/libc/include/ipc/fb.h |
---|
41,6 → 41,7 |
FB_PUTCHAR = IPC_FIRST_USER_METHOD, |
FB_CLEAR, |
FB_GET_CSIZE, |
FB_GET_COLOR_CAP, |
FB_CURSOR_VISIBILITY, |
FB_CURSOR_GOTO, |
FB_SCROLL, |
71,6 → 72,13 |
FB_SCREEN_RECLAIM |
} fb_request_t; |
enum { |
FB_CCAP_NONE = 0, |
FB_CCAP_STYLE, |
FB_CCAP_INDEXED, |
FB_CCAP_RGB |
}; |
#endif |
/** @} |
/branches/network/uspace/lib/libc/include/errno.h |
---|
35,12 → 35,13 |
#ifndef LIBC_ERRNO_H_ |
#define LIBC_ERRNO_H_ |
/* TODO: support threads/fibrils */ |
#include <kernel/errno.h> |
#include <fibril.h> |
extern int _errno; |
#define errno _errno |
#include <kernel/errno.h> |
#define EMFILE (-17) |
#define ENAMETOOLONG (-256) |
#define EISDIR (-257) |
/branches/network/uspace/lib/libc/include/sys/stat.h |
---|
36,7 → 36,26 |
#define LIBC_SYS_STAT_H_ |
#include <sys/types.h> |
#include <bool.h> |
#include <ipc/vfs.h> |
#include <ipc/devmap.h> |
struct stat { |
fs_handle_t fs_handle; |
dev_handle_t dev_handle; |
fs_index_t index; |
unsigned lnkcnt; |
bool is_file; |
off_t size; |
union { |
struct { |
dev_handle_t device; |
} devfs_stat; |
}; |
}; |
extern int fstat(int, struct stat *); |
extern int stat(const char *, struct stat *); |
extern int mkdir(const char *, mode_t); |
#endif |
/branches/network/uspace/lib/libc/generic/task.c |
---|
148,10 → 148,23 |
return 0; |
} |
int task_wait(task_id_t id) |
int task_wait(task_id_t id, task_exit_t *texit, int *retval) |
{ |
return (int) async_req_2_0(PHONE_NS, NS_TASK_WAIT, LOWER32(id), UPPER32(id)); |
ipcarg_t te, rv; |
int rc; |
rc = (int) async_req_2_2(PHONE_NS, NS_TASK_WAIT, LOWER32(id), |
UPPER32(id), &te, &rv); |
*texit = te; |
*retval = rv; |
return rc; |
} |
int task_retval(int val) |
{ |
return (int) async_req_1_0(PHONE_NS, NS_RETVAL, val); |
} |
/** @} |
*/ |
/branches/network/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/network/uspace/lib/libc/generic/as.c |
---|
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) && (((size_t) -incr) > heapsize)) |
return NULL; |
/* Check for too large value */ |
if ((incr > 0) && (incr + heapsize < heapsize)) |
return NULL; |
/* Check for too small values */ |
if ((incr < 0) && (incr + heapsize > heapsize)) |
return NULL; |
/* Check for user limit */ |
if ((maxheapsize != (size_t) (-1)) && (heapsize + incr) > maxheapsize) |
return NULL; |
rc = as_area_resize(&_heap, heapsize + incr, 0); |
if (rc != 0) |
return NULL; |
/* Compute start of new area */ |
res = (void *) &_heap + heapsize; |
heapsize += incr; |
return res; |
} |
/** Set maximum heap size and return pointer just after the heap */ |
void *set_maxheapsize(size_t mhs) |
{ |
maxheapsize = mhs; |
/* Return pointer to area not managed by sbrk */ |
return ((void *) &_heap + maxheapsize); |
} |
/** Return pointer to some unmapped area, where fits new as_area |
* |
* @param 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 == (size_t) -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/network/uspace/lib/libc/generic/string.c |
---|
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,7 → 611,7 |
* |
* @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; |
624,7 → 624,7 |
last = off; |
} |
return res; |
return (char *) res; |
} |
/** Insert a wide character into a wide string. |
/branches/network/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/network/uspace/lib/libc/generic/libc.c |
---|
52,11 → 52,8 |
#include <as.h> |
#include <loader/pcb.h> |
extern char _heap; |
extern int main(int argc, char *argv[]); |
int _errno; |
void _exit(int status) |
{ |
thread_exit(status); |
64,9 → 61,10 |
void __main(void *pcb_ptr) |
{ |
(void) as_area_create(&_heap, 1, AS_AREA_WRITE | AS_AREA_READ); |
_async_init(); |
int retval; |
__heap_init(); |
__async_init(); |
fibril_t *fibril = fibril_setup(); |
__tcb_set(fibril->tcb); |
79,15 → 77,17 |
if (__pcb == NULL) { |
argc = 0; |
argv = NULL; |
stdio_init(0, NULL); |
__stdio_init(0, NULL); |
} else { |
argc = __pcb->argc; |
argv = __pcb->argv; |
stdio_init(__pcb->filc, __pcb->filv); |
__stdio_init(__pcb->filc, __pcb->filv); |
} |
main(argc, argv); |
stdio_done(); |
retval = main(argc, argv); |
__stdio_done(); |
(void) task_retval(retval); |
} |
void __exit(void) |
/branches/network/uspace/lib/libc/generic/devmap.c |
---|
218,6 → 218,31 |
return phone; |
} |
int devmap_null_create(void) |
{ |
int phone = devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING); |
if (phone < 0) |
return -1; |
ipcarg_t null_id; |
int retval = async_req_0_1(phone, DEVMAP_DEVICE_NULL_CREATE, &null_id); |
if (retval != EOK) |
return -1; |
return (int) null_id; |
} |
void devmap_null_destroy(int null_id) |
{ |
int phone = devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING); |
if (phone < 0) |
return; |
async_req_1_0(phone, DEVMAP_DEVICE_NULL_DESTROY, (ipcarg_t) null_id); |
} |
ipcarg_t devmap_device_get_count(void) |
{ |
int phone = devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING); |
/branches/network/uspace/lib/libc/generic/async.c |
---|
738,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)) { |
/branches/network/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> |
137,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); |
198,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); |
230,7 → 230,7 |
vfs_connect(); |
ipc_call_t answer; |
aid_t req = async_send_4(vfs_phone, VFS_OPEN_NODE, node->fs_handle, |
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; |
252,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); |
270,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); |
297,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); |
314,95 → 314,115 |
return -1; |
} |
int fd_phone(int fildes) |
int fsync(int fildes) |
{ |
futex_down(&vfs_phone_futex); |
async_serialize_start(); |
vfs_connect(); |
ipcarg_t device; |
ipcarg_t rc = async_req_1_1(vfs_phone, VFS_DEVICE, fildes, &device); |
ipcarg_t rc = async_req_1_0(vfs_phone, VFS_IN_SYNC, fildes); |
async_serialize_end(); |
futex_up(&vfs_phone_futex); |
if (rc != EOK) |
return -1; |
return devmap_device_connect((dev_handle_t) device, 0); |
return (int) rc; |
} |
int fd_node(int fildes, fdi_node_t *node) |
off_t lseek(int fildes, off_t offset, int whence) |
{ |
ipcarg_t rc; |
futex_down(&vfs_phone_futex); |
async_serialize_start(); |
vfs_connect(); |
ipcarg_t fs_handle; |
ipcarg_t dev_handle; |
ipcarg_t index; |
ipcarg_t rc = async_req_1_3(vfs_phone, VFS_NODE, fildes, &fs_handle, |
&dev_handle, &index); |
ipcarg_t newoffs; |
rc = async_req_3_1(vfs_phone, VFS_IN_SEEK, fildes, offset, whence, |
&newoffs); |
async_serialize_end(); |
futex_up(&vfs_phone_futex); |
if (rc != EOK) |
return (off_t) -1; |
if (rc == EOK) { |
node->fs_handle = (fs_handle_t) fs_handle; |
node->dev_handle = (dev_handle_t) dev_handle; |
node->index = (fs_index_t) index; |
} |
return rc; |
return (off_t) newoffs; |
} |
int fsync(int fildes) |
int ftruncate(int fildes, off_t length) |
{ |
ipcarg_t rc; |
futex_down(&vfs_phone_futex); |
async_serialize_start(); |
vfs_connect(); |
ipcarg_t rc = async_req_1_0(vfs_phone, VFS_SYNC, fildes); |
rc = async_req_2_0(vfs_phone, VFS_IN_TRUNCATE, fildes, length); |
async_serialize_end(); |
futex_up(&vfs_phone_futex); |
return (int) rc; |
} |
off_t lseek(int fildes, off_t offset, int whence) |
int fstat(int fildes, struct stat *stat) |
{ |
ipcarg_t rc; |
aid_t req; |
futex_down(&vfs_phone_futex); |
async_serialize_start(); |
vfs_connect(); |
ipcarg_t newoffs; |
rc = async_req_3_1(vfs_phone, VFS_SEEK, fildes, offset, whence, |
&newoffs); |
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); |
if (rc != EOK) |
return (off_t) -1; |
return (off_t) newoffs; |
return rc; |
} |
int ftruncate(int fildes, off_t length) |
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(); |
rc = async_req_2_0(vfs_phone, VFS_TRUNCATE, fildes, length); |
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); |
return (int) rc; |
free(pa); |
return rc; |
} |
DIR *opendir(const char *dirname) |
452,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); |
482,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); |
529,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); |
598,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/network/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/network/uspace/lib/libc/generic/io/console.c |
---|
69,6 → 69,17 |
async_msg_1(phone, CONSOLE_CURSOR_VISIBILITY, show != false); |
} |
int console_get_color_cap(int phone, int *ccap) |
{ |
ipcarg_t ccap_tmp; |
int rc; |
rc = async_req_0_1(phone, CONSOLE_GET_COLOR_CAP, &ccap_tmp); |
*ccap = ccap_tmp; |
return rc; |
} |
void console_kcon_enable(int phone) |
{ |
async_msg_0(phone, CONSOLE_KCON_ENABLE); |
/branches/network/uspace/lib/libc/generic/io/io.c |
---|
89,7 → 89,7 |
static LIST_INITIALIZE(files); |
void stdio_init(int filc, fdi_node_t *filv[]) |
void __stdio_init(int filc, fdi_node_t *filv[]) |
{ |
if (filc > 0) { |
stdin = fopen_node(filv[0], "r"); |
113,7 → 113,7 |
} |
} |
void stdio_done(void) |
void __stdio_done(void) |
{ |
link_t *link = files.next; |
180,17 → 180,34 |
stream->buf_head = stream->buf; |
} |
static void _setvbuf(FILE *stream) |
{ |
/* FIXME: Use more complex rules for setting buffering options. */ |
switch (stream->fd) { |
case 1: |
setvbuf(stream, NULL, _IOLBF, BUFSIZ); |
break; |
case 0: |
case 2: |
setvbuf(stream, NULL, _IONBF, 0); |
break; |
default: |
setvbuf(stream, NULL, _IOFBF, BUFSIZ); |
} |
} |
/** Allocate stream buffer. */ |
static int _fallocbuf(FILE *stream) |
{ |
assert(stream->buf == NULL); |
stream->buf = malloc(stream->buf_size); |
if (stream->buf == NULL) { |
errno = ENOMEM; |
return -1; |
} |
stream->buf_head = stream->buf; |
return 0; |
} |
225,9 → 242,7 |
stream->eof = false; |
stream->klog = false; |
stream->phone = -1; |
/* FIXME: Should select buffering type based on what was opened. */ |
setvbuf(stream, NULL, _IOFBF, BUFSIZ); |
_setvbuf(stream); |
list_append(&stream->link, &files); |
248,9 → 263,7 |
stream->eof = false; |
stream->klog = false; |
stream->phone = -1; |
/* FIXME: Should select buffering type based on what was opened. */ |
setvbuf(stream, NULL, _IOLBF, BUFSIZ); |
_setvbuf(stream); |
list_append(&stream->link, &files); |
281,9 → 294,7 |
stream->eof = false; |
stream->klog = false; |
stream->phone = -1; |
/* FIXME: Should select buffering type based on what was opened. */ |
setvbuf(stream, NULL, _IOLBF, BUFSIZ); |
_setvbuf(stream); |
list_append(&stream->link, &files); |
331,10 → 342,10 |
{ |
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); |
379,14 → 390,14 |
static void _fflushbuf(FILE *stream) |
{ |
size_t bytes_used; |
if (!stream->buf || stream->btype == _IONBF || stream->error) |
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; |
} |
409,44 → 420,46 |
size_t i; |
uint8_t b; |
bool need_flush; |
/* If not buffered stream, write out directly. */ |
if (stream->btype == _IONBF) |
return _fwrite(buf, size, nmemb, stream); |
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) { |
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) |
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); |
453,10 → 466,10 |
need_flush = false; |
} |
} |
if (need_flush) |
fflush(stream); |
return (total_written / size); |
} |
495,13 → 508,13 |
int fgetc(FILE *stream) |
{ |
char c; |
/* This could be made faster by only flushing when needed. */ |
if (stdout) |
fflush(stdout); |
if (stderr) |
fflush(stderr); |
if (fread(&c, sizeof(char), 1, stream) < sizeof(char)) |
return EOF; |
534,7 → 547,7 |
int fflush(FILE *stream) |
{ |
_fflushbuf(stream); |
if (stream->klog) { |
klog_update(); |
return EOK; |
/branches/network/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); |
} |
/branches/network/uspace/lib/libc/Makefile |
---|
49,6 → 49,7 |
generic/cap.c \ |
generic/devmap.c \ |
generic/event.c \ |
generic/errno.c \ |
generic/mem.c \ |
generic/string.c \ |
generic/fibril.c \ |
68,7 → 69,7 |
generic/io/vsnprintf.c \ |
generic/io/printf_core.c \ |
generic/io/console.c \ |
malloc/malloc.c \ |
generic/malloc.c \ |
generic/sysinfo.c \ |
generic/ipc.c \ |
generic/async.c \ |
105,7 → 106,7 |
clean: |
-rm -f include/kernel include/arch include/libarch libc.a arch/$(UARCH)/_link.ld Makefile.depend |
find generic/ arch/$(UARCH)/ malloc -name '*.o' -follow -exec rm \{\} \; |
find generic/ arch/$(UARCH)/ -name '*.o' -follow -exec rm \{\} \; |
depend: kerninc |
-makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(ARCH_SOURCES) $(GENERIC_SOURCES) > Makefile.depend 2> /dev/null |
/branches/network/uspace/lib/libc/arch/sparc64/include/stack.h |
---|
45,6 → 45,11 |
*/ |
#define STACK_WINDOW_SAVE_AREA_SIZE (16 * STACK_ITEM_SIZE) |
/* |
* Six extended words for first six arguments. |
*/ |
#define STACK_ARG_SAVE_AREA_SIZE (6 * STACK_ITEM_SIZE) |
/** |
* By convention, the actual top of the stack is %sp + STACK_BIAS. |
*/ |
/branches/network/uspace/lib/libc/arch/sparc64/include/fibril.h |
---|
39,7 → 39,7 |
#include <sys/types.h> |
#include <align.h> |
#define SP_DELTA STACK_WINDOW_SAVE_AREA_SIZE |
#define SP_DELTA (STACK_WINDOW_SAVE_AREA_SIZE + STACK_ARG_SAVE_AREA_SIZE) |
#ifdef context_set |
#undef context_set |
/branches/network/uspace/lib/libc/arch/ia64/Makefile.inc |
---|
37,7 → 37,7 |
arch/$(UARCH)/src/tls.c \ |
arch/$(UARCH)/src/ddi.c |
CFLAGS += -fno-unwind-tables -DMALLOC_ALIGNMENT_16 |
CFLAGS += -fno-unwind-tables |
LFLAGS += -N $(SOFTINT_PREFIX)/libsoftint.a |
ENDIANESS = LE |