Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 4326 → Rev 4327

/branches/network/uspace/lib/libc/include/console.h
27,7 → 27,7
*/
 
/** @addtogroup libc
* @{
* @{
*/
/** @file
*/
40,17 → 40,15
#include <sys/types.h>
#include <bool.h>
 
extern void console_open(bool);
extern int console_open(bool);
extern void console_close(void);
 
extern int console_phone_get(bool);
extern void console_wait(void);
 
extern void console_clear(void);
extern void console_goto(int, int);
extern void console_putchar(wchar_t);
extern ssize_t console_write(const char *buf, size_t nbyte);
extern void console_putstr(const char *s);
extern ssize_t console_write(const char *, size_t);
extern void console_putstr(const char *);
extern void console_flush(void);
 
extern int console_get_size(int *, int *);
62,6 → 60,6
extern void console_kcon_enable(void);
 
#endif
 
/** @}
*/
/branches/network/uspace/lib/libc/include/string.h
45,8 → 45,8
/**< No size limit constant */
#define STR_NO_LIMIT ((size_t) -1)
 
/**< Maximum size of a string containing cnt characters */
#define STR_BOUNDS(cnt) (cnt << 2)
/**< Maximum size of a string containing @c length characters */
#define STR_BOUNDS(length) ((length) << 2)
 
extern wchar_t str_decode(const char *str, size_t *offset, size_t sz);
extern int chr_encode(const wchar_t ch, char *str, size_t *offset, size_t sz);
69,34 → 69,26
extern int str_cmp(const char *s1, const char *s2);
extern int str_lcmp(const char *s1, const char *s2, count_t max_len);
 
extern void str_ncpy(char *dst, const char *src, size_t size);
extern void str_cpy(char *dest, size_t size, const char *src);
extern void str_ncpy(char *dest, size_t size, const char *src, size_t n);
extern void str_append(char *dest, size_t size, const char *src);
 
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 bool wstr_linsert(wchar_t *str, wchar_t ch, count_t pos, count_t max_pos);
extern bool wstr_remove(wchar_t *str, count_t pos);
 
extern char *str_dup(const char *);
 
/*
* TODO: Get rid of this.
*/
 
extern int strcmp(const char *, const char *);
extern int strncmp(const char *, const char *, size_t);
extern int stricmp(const char *, const char *);
 
extern char *strcpy(char *, const char *);
extern char *strncpy(char *, const char *, size_t);
 
extern char *strcat(char *, const char *);
 
extern size_t strlen(const char *);
 
extern char *strdup(const char *);
 
extern char *strchr(const char *, int);
extern char *strrchr(const char *, int);
 
extern long int strtol(const char *, char **, int);
extern unsigned long strtoul(const char *, char **, int);
 
/branches/network/uspace/lib/libc/include/vfs/vfs.h
39,7 → 39,7
 
extern char *absolutize(const char *, size_t *);
 
extern int mount(const char *, const char *, const char *,
extern int mount(const char *, const char *, const char *, const char *,
const unsigned int flags);
 
#endif
/branches/network/uspace/lib/libc/include/async.h
98,22 → 98,22
 
/* Wrappers for simple communication */
#define async_msg_0(phone, method) \
ipc_call_async_0((phone), (method), NULL, NULL, !in_interrupt_handler())
ipc_call_async_0((phone), (method), NULL, NULL, true)
#define async_msg_1(phone, method, arg1) \
ipc_call_async_1((phone), (method), (arg1), NULL, NULL, \
!in_interrupt_handler())
true)
#define async_msg_2(phone, method, arg1, arg2) \
ipc_call_async_2((phone), (method), (arg1), (arg2), NULL, NULL, \
!in_interrupt_handler())
true)
#define async_msg_3(phone, method, arg1, arg2, arg3) \
ipc_call_async_3((phone), (method), (arg1), (arg2), (arg3), NULL, NULL, \
!in_interrupt_handler())
true)
#define async_msg_4(phone, method, arg1, arg2, arg3, arg4) \
ipc_call_async_4((phone), (method), (arg1), (arg2), (arg3), (arg4), NULL, \
NULL, !in_interrupt_handler())
NULL, true)
#define async_msg_5(phone, method, arg1, arg2, arg3, arg4, arg5) \
ipc_call_async_5((phone), (method), (arg1), (arg2), (arg3), (arg4), \
(arg5), NULL, NULL, !in_interrupt_handler())
(arg5), NULL, NULL, true)
 
/*
* User-friendly wrappers for async_req_fast() and async_req_slow(). The macros
253,8 → 253,6
fibril_dec_sercount();
}
 
extern bool in_interrupt_handler(void);
 
extern atomic_t async_futex;
 
#endif
/branches/network/uspace/lib/libc/include/stdio.h
49,7 → 49,7
int n; \
n = snprintf(buf, sizeof(buf), fmt, ##__VA_ARGS__); \
if (n > 0) \
(void) __SYSCALL3(SYS_KLOG, 1, (sysarg_t) buf, strlen(buf)); \
(void) __SYSCALL3(SYS_KLOG, 1, (sysarg_t) buf, str_size(buf)); \
}
 
typedef struct {
/branches/network/uspace/lib/libc/include/thread.h
45,7 → 45,7
extern void __thread_main(uspace_arg_t *);
 
extern int thread_create(void (*)(void *), void *, char *, thread_id_t *);
extern void thread_exit(int);
extern void thread_exit(int) __attribute__ ((noreturn));
extern void thread_detach(thread_id_t);
extern int thread_join(thread_id_t);
extern thread_id_t thread_get_id(void);
/branches/network/uspace/lib/libc/include/io/stream.h
37,15 → 37,11
 
#include <libarch/types.h>
 
#define EMFILE -17
#define EMFILE -17
 
extern ssize_t read_stdin(void *, size_t);
extern void klog_update(void);
 
extern ssize_t read_stdin(void *, size_t);
extern ssize_t write_stdout(const void *, size_t);
extern ssize_t write_stderr(const void *, size_t);
extern int flush_stdout(void);
 
#endif
 
/** @}
/branches/network/uspace/lib/libc/include/ipc/fb.h
66,7 → 66,9
FB_ANIM_CHGVP,
FB_ANIM_START,
FB_ANIM_STOP,
FB_POINTER_MOVE
FB_POINTER_MOVE,
FB_SCREEN_YIELD,
FB_SCREEN_RECLAIM
} fb_request_t;
 
#endif
/branches/network/uspace/lib/libc/generic/kbd.c
42,7 → 42,7
 
int kbd_get_event(kbd_event_t *ev)
{
int cons_phone = console_phone_get(true);
int cons_phone = console_open(true);
ipcarg_t r0, r1, r2, r3;
int rc;
 
/branches/network/uspace/lib/libc/generic/console.c
32,8 → 32,9
* @{
*/
/** @file
*/
*/
 
#include <libc.h>
#include <async.h>
#include <io/stream.h>
#include <ipc/console.h>
45,7 → 46,7
static int console_phone = -1;
 
/** Size of cbuffer. */
#define CBUFFER_SIZE 256
#define CBUFFER_SIZE 256
 
/** Buffer for writing characters to the console. */
static char cbuffer[CBUFFER_SIZE];
56,92 → 57,56
/** Pointer to first available field in cbuffer. */
static char *cbp = cbuffer;
 
static ssize_t cons_write(const char *buf, size_t nbyte);
static void cons_putchar(wchar_t c);
 
static void cbuffer_flush(void);
static void cbuffer_drain(void);
static inline void cbuffer_putc(int c);
 
 
void console_open(bool blocking)
/** Write one character to the console via IPC. */
static void cons_putchar(wchar_t c)
{
if (console_phone < 0) {
int phone;
if (blocking) {
phone = ipc_connect_me_to_blocking(PHONE_NS,
SERVICE_CONSOLE, 0, 0);
} else {
phone = ipc_connect_me_to(PHONE_NS, SERVICE_CONSOLE, 0,
0);
}
if (phone >= 0)
console_phone = phone;
}
console_wait();
async_msg_1(console_phone, CONSOLE_PUTCHAR, c);
}
 
void console_close(void)
/** Write characters to the console via IPC or to klog */
static ssize_t cons_write(const char *buf, size_t size)
{
console_open(false);
if (console_phone >= 0) {
if (ipc_hangup(console_phone) == 0) {
console_phone = -1;
async_serialize_start();
ipc_call_t answer;
aid_t req = async_send_0(console_phone, CONSOLE_WRITE, &answer);
ipcarg_t rc = ipc_data_write_start(console_phone, (void *) buf, size);
if (rc != EOK) {
async_wait_for(req, NULL);
async_serialize_end();
return (ssize_t) rc;
}
}
async_wait_for(req, &rc);
async_serialize_end();
if (rc == EOK)
return (ssize_t) IPC_GET_ARG1(answer);
else
return -1;
} else
return __SYSCALL3(SYS_KLOG, 1, (sysarg_t) buf, size);
}
 
int console_phone_get(bool blocking)
{
if (console_phone < 0)
console_open(blocking);
return console_phone;
}
 
void console_wait(void)
{
while (console_phone < 0)
console_open(true);
}
 
void console_clear(void)
{
int cons_phone = console_phone_get(true);
 
cbuffer_drain();
async_msg_0(cons_phone, CONSOLE_CLEAR);
}
 
void console_goto(int row, int col)
{
int cons_phone = console_phone_get(true);
 
cbuffer_flush();
async_msg_2(cons_phone, CONSOLE_GOTO, row, col);
}
 
void console_putchar(wchar_t c)
{
// cbuffer_putc(c);
cbuffer_flush();
cons_putchar(c);
}
 
/** Write all data from output buffer to the console. */
static void cbuffer_flush(void)
{
int rc;
int len;
 
len = cbp - cbuffer;
 
size_t len = cbp - cbuffer;
while (len > 0) {
rc = cons_write(cbuffer, cbp - cbuffer);
ssize_t rc = cons_write(cbuffer, cbp - cbuffer);
if (rc < 0)
return;
 
len -= rc;
}
 
cbp = cbuffer;
}
 
152,145 → 117,158
}
 
/** Write one character to the output buffer. */
static inline void cbuffer_putc(int c)
static inline void cbuffer_putc(char c)
{
if (cbp == cbuffer_end)
cbuffer_flush();
 
*cbp++ = c;
 
if (c == '\n')
cbuffer_flush();
}
 
/** Write one character to the console via IPC. */
static void cons_putchar(wchar_t c)
int console_open(bool blocking)
{
int cons_phone = console_phone_get(true);
async_msg_1(cons_phone, CONSOLE_PUTCHAR, c);
}
 
/** Write characters to the console via IPC. */
static ssize_t cons_write(const char *buf, size_t nbyte)
{
int cons_phone = console_phone_get(true);
ipcarg_t rc;
ipc_call_t answer;
aid_t req;
 
async_serialize_start();
if (console_phone < 0) {
int phone;
if (blocking)
phone = ipc_connect_me_to_blocking(PHONE_NS,
SERVICE_CONSOLE, 0, 0);
else
phone = ipc_connect_me_to(PHONE_NS,
SERVICE_CONSOLE, 0, 0);
if (phone >= 0)
console_phone = phone;
}
req = async_send_0(cons_phone, CONSOLE_WRITE, &answer);
rc = ipc_data_write_start(cons_phone, (void *) buf, nbyte);
 
if (rc != EOK) {
async_wait_for(req, NULL);
async_serialize_end();
return (ssize_t) rc;
}
 
async_wait_for(req, &rc);
async_serialize_end();
 
if (rc == EOK)
return (ssize_t) IPC_GET_ARG1(answer);
else
return -1;
return console_phone;
}
 
/** Write characters to the console. */
ssize_t console_write(const char *buf, size_t nbyte)
void console_close(void)
{
size_t left;
 
left = nbyte;
 
while (left > 0) {
cbuffer_putc(*buf++);
--left;
if (console_phone >= 0) {
if (ipc_hangup(console_phone) == 0)
console_phone = -1;
}
 
return nbyte;
}
 
/** Write a NULL-terminated string to the console. */
void console_putstr(const char *s)
void console_wait(void)
{
size_t len;
ssize_t rc;
 
len = strlen(s);
while (len > 0) {
rc = console_write(s, len);
if (rc < 0)
return; /* Error */
s += rc;
len -= rc;
}
while (console_phone < 0)
console_open(true);
}
 
/** Flush all output to the console. */
void console_flush(void)
void console_clear(void)
{
int cons_phone = console_phone_get(false);
 
cbuffer_flush();
async_msg_0(cons_phone, CONSOLE_FLUSH);
console_wait();
cbuffer_drain();
async_msg_0(console_phone, CONSOLE_CLEAR);
}
 
int console_get_size(int *rows, int *cols)
{
int cons_phone = console_phone_get(true);
ipcarg_t r, c;
int rc;
 
rc = async_req_0_2(cons_phone, CONSOLE_GETSIZE, &r, &c);
 
console_wait();
ipcarg_t r;
ipcarg_t c;
int rc = async_req_0_2(console_phone, CONSOLE_GETSIZE, &r, &c);
*rows = (int) r;
*cols = (int) c;
 
return rc;
}
 
void console_set_style(int style)
{
int cons_phone = console_phone_get(true);
 
console_wait();
cbuffer_flush();
async_msg_1(cons_phone, CONSOLE_SET_STYLE, style);
async_msg_1(console_phone, CONSOLE_SET_STYLE, style);
}
 
void console_set_color(int fg_color, int bg_color, int flags)
{
int cons_phone = console_phone_get(true);
 
console_wait();
cbuffer_flush();
async_msg_3(cons_phone, CONSOLE_SET_COLOR, fg_color, bg_color, flags);
async_msg_3(console_phone, CONSOLE_SET_COLOR, fg_color, bg_color, flags);
}
 
void console_set_rgb_color(int fg_color, int bg_color)
{
int cons_phone = console_phone_get(true);
 
console_wait();
cbuffer_flush();
async_msg_2(cons_phone, CONSOLE_SET_RGB_COLOR, fg_color, bg_color);
async_msg_2(console_phone, CONSOLE_SET_RGB_COLOR, fg_color, bg_color);
}
 
void console_cursor_visibility(int show)
{
int cons_phone = console_phone_get(true);
 
console_wait();
cbuffer_flush();
async_msg_1(cons_phone, CONSOLE_CURSOR_VISIBILITY, show != 0);
async_msg_1(console_phone, CONSOLE_CURSOR_VISIBILITY, show != 0);
}
 
void console_kcon_enable(void)
{
int cons_phone = console_phone_get(true);
console_wait();
cbuffer_flush();
async_msg_0(console_phone, CONSOLE_KCON_ENABLE);
}
 
void console_goto(int row, int col)
{
console_wait();
cbuffer_flush();
async_msg_0(cons_phone, CONSOLE_KCON_ENABLE);
async_msg_2(console_phone, CONSOLE_GOTO, row, col);
}
 
void console_putchar(wchar_t c)
{
console_wait();
cbuffer_flush();
cons_putchar(c);
}
 
/** Write characters to the console. */
ssize_t console_write(const char *buf, size_t size)
{
size_t left = size;
while (left > 0) {
cbuffer_putc(*buf++);
left--;
}
return size;
}
 
/** Write a NULL-terminated string to the console. */
void console_putstr(const char *str)
{
size_t left = str_size(str);
while (left > 0) {
ssize_t rc = console_write(str, left);
if (rc < 0) {
/* Error */
return;
}
str += rc;
left -= rc;
}
}
 
/** Flush all output to the console or klog. */
void console_flush(void)
{
cbuffer_flush();
if (console_phone >= 0)
async_msg_0(console_phone, CONSOLE_FLUSH);
}
 
/** @}
*/
/branches/network/uspace/lib/libc/generic/getopt.c
241,7 → 241,7
}
}
if ((optchar = (int)*place++) == (int)':' ||
(oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
(oli = str_chr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
/* option letter unknown or ':' */
if (!*place)
++optind;
377,20 → 377,20
nonopt_start = nonopt_end = -1;
return -1;
}
if ((has_equal = strchr(current_argv, '=')) != NULL) {
if ((has_equal = str_chr(current_argv, '=')) != NULL) {
/* argument found (--option=arg) */
current_argv_len = has_equal - current_argv;
has_equal++;
} else
current_argv_len = strlen(current_argv);
current_argv_len = str_size(current_argv);
for (i = 0; long_options[i].name; i++) {
/* find matching long option */
if (strncmp(current_argv, long_options[i].name,
current_argv_len))
if (str_lcmp(current_argv, long_options[i].name,
str_nlength(current_argv, current_argv_len)))
continue;
 
if (strlen(long_options[i].name) ==
if (str_size(long_options[i].name) ==
(unsigned)current_argv_len) {
/* exact match */
match = i;
/branches/network/uspace/lib/libc/generic/string.c
35,11 → 35,13
 
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <limits.h>
#include <ctype.h>
#include <malloc.h>
#include <errno.h>
#include <align.h>
#include <mem.h>
#include <string.h>
 
/** Byte mask consisting of lowest @n bits (out of 8) */
461,40 → 463,91
 
}
 
/** Copy NULL-terminated string.
/** Copy string.
*
* Copy source string @a src to destination buffer @a dst.
* No more than @a size bytes are written. NULL-terminator is always
* written after the last succesfully copied character (i.e. if the
* destination buffer is has at least 1 byte, it will be always
* NULL-terminated).
* Copy source string @a src to destination buffer @a dest.
* No more than @a size bytes are written. If the size of the output buffer
* is at least one byte, the output string will always be well-formed, i.e.
* null-terminated and containing only complete characters.
*
* @param dst Destination buffer.
* @param count Size of the destination buffer (must be > 0).
* @param src Source string.
*/
void str_cpy(char *dest, size_t size, const char *src)
{
wchar_t ch;
size_t src_off;
size_t dest_off;
 
/* There must be space for a null terminator in the buffer. */
assert(size > 0);
src_off = 0;
dest_off = 0;
 
while ((ch = str_decode(src, &src_off, STR_NO_LIMIT)) != 0) {
if (chr_encode(ch, dest, &dest_off, size - 1) != EOK)
break;
}
 
dest[dest_off] = '\0';
}
 
/** Copy size-limited substring.
*
* Copy prefix of string @a src of max. size @a size to destination buffer
* @a dest. No more than @a size bytes are written. The output string will
* always be well-formed, i.e. null-terminated and containing only complete
* characters.
*
* No more than @a n bytes are read from the input string, so it does not
* have to be null-terminated.
*
* @param dst Destination buffer.
* @param count Size of the destination buffer.
*
* @param count Size of the destination buffer (must be > 0).
* @param src Source string.
* @param n Maximum number of bytes to read from @a src.
*/
void str_ncpy(char *dst, const char *src, size_t size)
void str_ncpy(char *dest, size_t size, const char *src, size_t n)
{
/* No space for the NULL-terminator in the buffer */
if (size == 0)
return;
wchar_t ch;
size_t str_off = 0;
size_t dst_off = 0;
size_t src_off;
size_t dest_off;
 
/* There must be space for a null terminator in the buffer. */
assert(size > 0);
while ((ch = str_decode(src, &str_off, STR_NO_LIMIT)) != 0) {
if (chr_encode(ch, dst, &dst_off, size) != EOK)
src_off = 0;
dest_off = 0;
 
while ((ch = str_decode(src, &src_off, n)) != 0) {
if (chr_encode(ch, dest, &dest_off, size - 1) != EOK)
break;
}
if (dst_off >= size)
dst[size - 1] = 0;
else
dst[dst_off] = 0;
 
dest[dest_off] = '\0';
}
 
/** Append one string to another.
*
* Append source string @a src to string in destination buffer @a dest.
* Size of the destination buffer is @a dest. If the size of the output buffer
* is at least one byte, the output string will always be well-formed, i.e.
* null-terminated and containing only complete characters.
*
* @param dst Destination buffer.
* @param count Size of the destination buffer.
* @param src Source string.
*/
void str_append(char *dest, size_t size, const char *src)
{
size_t dstr_size;
 
dstr_size = str_size(dest);
str_cpy(dest + dstr_size, size - dstr_size, src);
}
 
/** Copy NULL-terminated wide string to string
*
* Copy source wide string @a src to destination buffer @a dst.
535,21 → 588,45
* @param ch Character to look for.
*
* @return Pointer to character in @a str or NULL if not found.
*
*/
const char *str_chr(const char *str, wchar_t ch)
{
wchar_t acc;
size_t off = 0;
size_t last = 0;
while ((acc = str_decode(str, &off, STR_NO_LIMIT)) != 0) {
if (acc == ch)
return (str + off);
return (str + last);
last = off;
}
return NULL;
}
 
/** Find last occurence of character in string.
*
* @param str String to search.
* @param ch Character to look for.
*
* @return Pointer to character in @a str or NULL if not found.
*/
const char *str_rchr(const char *str, wchar_t ch)
{
wchar_t acc;
size_t off = 0;
size_t last = 0;
char *res = NULL;
while ((acc = str_decode(str, &off, STR_NO_LIMIT)) != 0) {
if (acc == ch)
res = (str + last);
last = off;
}
return res;
}
 
/** Insert a wide character into a wide string.
*
* Insert a wide character into a wide string at position
606,42 → 683,6
return true;
}
 
/** Count the number of characters in the string, not including terminating 0.
*
* @param str String.
* @return Number of characters in string.
*/
size_t strlen(const char *str)
{
size_t counter = 0;
 
while (str[counter] != 0)
counter++;
 
return counter;
}
 
int strcmp(const char *a, const char *b)
{
int c = 0;
while (a[c] && b[c] && (!(a[c] - b[c])))
c++;
return (a[c] - b[c]);
}
 
int strncmp(const char *a, const char *b, size_t n)
{
size_t c = 0;
 
while (c < n && a[c] && b[c] && (!(a[c] - b[c])))
c++;
return ( c < n ? a[c] - b[c] : 0);
}
 
int stricmp(const char *a, const char *b)
{
int c = 0;
652,44 → 693,6
return (tolower(a[c]) - tolower(b[c]));
}
 
/** Return pointer to the first occurence of character c in string.
*
* @param str Scanned string.
* @param c Searched character (taken as one byte).
* @return Pointer to the matched character or NULL if it is not
* found in given string.
*/
char *strchr(const char *str, int c)
{
while (*str != '\0') {
if (*str == (char) c)
return (char *) str;
str++;
}
 
return NULL;
}
 
/** Return pointer to the last occurence of character c in string.
*
* @param str Scanned string.
* @param c Searched character (taken as one byte).
* @return Pointer to the matched character or NULL if it is not
* found in given string.
*/
char *strrchr(const char *str, int c)
{
char *retval = NULL;
 
while (*str != '\0') {
if (*str == (char) c)
retval = (char *) str;
str++;
}
 
return (char *) retval;
}
 
/** Convert string to a number.
* Core of strtol and strtoul functions.
*
839,44 → 842,15
return (sgn ? -number : number);
}
 
char *strcpy(char *dest, const char *src)
char *str_dup(const char *src)
{
char *orig = dest;
while ((*(dest++) = *(src++)))
;
return orig;
}
size_t size = str_size(src);
void *dest = malloc(size + 1);
 
char *strncpy(char *dest, const char *src, size_t n)
{
char *orig = dest;
while ((*(dest++) = *(src++)) && --n)
;
return orig;
}
 
char *strcat(char *dest, const char *src)
{
char *orig = dest;
while (*dest++)
;
--dest;
while ((*dest++ = *src++))
;
return orig;
}
 
char * strdup(const char *s1)
{
size_t len = strlen(s1) + 1;
void *ret = malloc(len);
 
if (ret == NULL)
if (dest == NULL)
return (char *) NULL;
 
return (char *) memcpy(ret, s1, len);
return (char *) memcpy(dest, src, size + 1);
}
 
char *strtok(char *s, const char *delim)
894,11 → 868,11
s = *next;
 
/* Skip over leading delimiters. */
while (*s && (strchr(delim, *s) != NULL)) ++s;
while (*s && (str_chr(delim, *s) != NULL)) ++s;
start = s;
 
/* Skip over token characters. */
while (*s && (strchr(delim, *s) == NULL)) ++s;
while (*s && (str_chr(delim, *s) == NULL)) ++s;
end = s;
*next = (*s ? s + 1 : s);
 
/branches/network/uspace/lib/libc/generic/loader.c
180,7 → 180,7
dp = arg_buf;
 
while (*ap != NULL) {
str_ncpy(dp, *ap, buffer_size - (dp - arg_buf));
str_cpy(dp, buffer_size - (dp - arg_buf), *ap);
dp += str_size(*ap) + 1;
 
++ap;
/branches/network/uspace/lib/libc/generic/thread.c
130,6 → 130,8
void thread_exit(int status)
{
__SYSCALL1(SYS_THREAD_EXIT, (sysarg_t) status);
for (;;)
;
}
 
/** Detach thread.
152,6 → 154,7
*/
int thread_join(thread_id_t thread)
{
return 0;
}
 
/** Get current thread ID.
/branches/network/uspace/lib/libc/generic/libc.c
48,6 → 48,7
#include <ipc/ipc.h>
#include <async.h>
#include <as.h>
#include <console.h>
#include <loader/pcb.h>
 
extern char _heap;
83,6 → 84,7
}
 
main(argc, argv);
console_flush();
}
 
void __exit(void)
/branches/network/uspace/lib/libc/generic/async.c
30,64 → 30,65
* @{
*/
/** @file
*/
*/
 
/**
* Asynchronous library
*
* The aim of this library is facilitating writing programs utilizing the
* asynchronous nature of HelenOS IPC, yet using a normal way of programming.
* The aim of this library is to provide a facility for writing programs which
* utilize the asynchronous nature of HelenOS IPC, yet using a normal way of
* programming.
*
* You should be able to write very simple multithreaded programs, the async
* framework will automatically take care of most synchronization problems.
*
* Default semantics:
* - async_send_*(): send asynchronously. If the kernel refuses to send
* more messages, [ try to get responses from kernel, if
* nothing found, might try synchronous ]
* - async_send_*(): Send asynchronously. If the kernel refuses to send
* more messages, [ try to get responses from kernel, if
* nothing found, might try synchronous ]
*
* Example of use (pseudo C):
*
*
* 1) Multithreaded client application
*
* fibril_create(fibril1, ...);
* fibril_create(fibril2, ...);
* ...
*
* int fibril1(void *arg)
* {
* conn = ipc_connect_me_to();
* c1 = async_send(conn);
* c2 = async_send(conn);
* async_wait_for(c1);
* async_wait_for(c2);
* ...
* }
* fibril_create(fibril1, ...);
* fibril_create(fibril2, ...);
* ...
*
* int fibril1(void *arg)
* {
* conn = ipc_connect_me_to();
* c1 = async_send(conn);
* c2 = async_send(conn);
* async_wait_for(c1);
* async_wait_for(c2);
* ...
* }
*
*
* 2) Multithreaded server application
* main()
* {
* async_manager();
* }
*
*
* my_client_connection(icallid, *icall)
* {
* if (want_refuse) {
* ipc_answer_0(icallid, ELIMIT);
* return;
* }
* ipc_answer_0(icallid, EOK);
* main()
* {
* async_manager();
* }
*
* callid = async_get_call(&call);
* handle_call(callid, call);
* ipc_answer_2(callid, 1, 2, 3);
* my_client_connection(icallid, *icall)
* {
* if (want_refuse) {
* ipc_answer_0(icallid, ELIMIT);
* return;
* }
* ipc_answer_0(icallid, EOK);
*
* callid = async_get_call(&call);
* ....
* }
* callid = async_get_call(&call);
* handle_call(callid, call);
* ipc_answer_2(callid, 1, 2, 3);
*
* callid = async_get_call(&call);
* ...
* }
*
*/
 
#include <futex.h>
104,24 → 105,26
#include <bool.h>
 
atomic_t async_futex = FUTEX_INITIALIZER;
static hash_table_t conn_hash_table;
static LIST_INITIALIZE(timeout_list);
 
/** Structures of this type represent a waiting fibril. */
typedef struct {
/** Expiration time. */
struct timeval expires;
struct timeval expires;
/** If true, this struct is in the timeout list. */
int inlist;
bool inlist;
/** Timeout list link. */
link_t link;
 
/** Identification of and link to the waiting fibril. */
fid_t fid;
/** If true, this fibril is currently active. */
int active;
bool active;
/** If true, we have timed out. */
int timedout;
bool timedout;
} awaiter_t;
 
typedef struct {
128,10 → 131,11
awaiter_t wdata;
/** If reply was received. */
int done;
bool done;
/** Pointer to where the answer data is stored. */
ipc_call_t *dataptr;
 
ipc_call_t *dataptr;
ipcarg_t retval;
} amsg_t;
 
147,24 → 151,24
 
typedef struct {
awaiter_t wdata;
 
/** Hash table link. */
link_t link;
 
/** Incoming phone hash. */
ipcarg_t in_phone_hash;
 
ipcarg_t in_phone_hash;
/** Messages that should be delivered to this fibril. */
link_t msg_queue;
link_t msg_queue;
/** Identification of the opening call. */
ipc_callid_t callid;
/** Call data of the opening call. */
ipc_call_t call;
 
/** Identification of the closing call. */
ipc_callid_t close_callid;
 
/** Fibril function that will be used to handle the connection. */
void (*cfibril)(ipc_callid_t, ipc_call_t *);
} connection_t;
172,12 → 176,6
/** Identifier of the incoming connection handled by the current fibril. */
__thread connection_t *FIBRIL_connection;
 
/**
* If true, it is forbidden to use async_req functions and all preemption is
* disabled.
*/
__thread int _in_interrupt_handler;
 
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);
 
185,6 → 183,7
* Pointer to a fibril function that will be used to handle connections.
*/
static async_client_conn_t client_connection = default_client_connection;
 
/**
* Pointer to a fibril function that will be used to handle interrupt
* notifications.
191,46 → 190,39
*/
static async_client_conn_t interrupt_received = default_interrupt_received;
 
/*
* Getter for _in_interrupt_handler. We need to export the value of this thread
* local variable to other modules, but the binutils 2.18 linkers die on an
* attempt to export this symbol in the header file. For now, consider this as a
* workaround.
*/
bool in_interrupt_handler(void)
{
return _in_interrupt_handler;
}
 
#define CONN_HASH_TABLE_CHAINS 32
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.
*
* @param key Pointer to source phone hash.
* @param key Pointer to source phone hash.
*
* @return Index into the connection hash table.
* @return Index into the connection hash table.
*
*/
static hash_index_t conn_hash(unsigned long *key)
{
assert(key);
return ((*key) >> 4) % CONN_HASH_TABLE_CHAINS;
return (((*key) >> 4) % CONN_HASH_TABLE_CHAINS);
}
 
/** Compare hash table item with a key.
*
* @param key Array containing the source phone hash as the only item.
* @param keys Expected 1 but ignored.
* @param item Connection hash table item.
* @param key Array containing the source phone hash as the only item.
* @param keys Expected 1 but ignored.
* @param item Connection hash table item.
*
* @return True on match, false otherwise.
* @return True on match, false otherwise.
*
*/
static int conn_compare(unsigned long key[], hash_count_t keys, link_t *item)
{
connection_t *hs;
 
hs = hash_table_get_instance(item, connection_t, link);
return key[0] == hs->in_phone_hash;
connection_t *hs = hash_table_get_instance(item, connection_t, link);
return (key[0] == hs->in_phone_hash);
}
 
/** Connection hash table removal callback function.
238,7 → 230,8
* This function is called whenever a connection is removed from the connection
* hash table.
*
* @param item Connection hash table item being removed.
* @param item Connection hash table item being removed.
*
*/
static void conn_remove(link_t *item)
{
255,23 → 248,24
 
/** Sort in current fibril's timeout request.
*
* @param wd Wait data of the current fibril.
* @param wd Wait data of the current fibril.
*
*/
static void insert_timeout(awaiter_t *wd)
{
link_t *tmp;
awaiter_t *cur;
 
wd->timedout = 0;
wd->inlist = 1;
 
tmp = timeout_list.next;
wd->timedout = false;
wd->inlist = true;
link_t *tmp = timeout_list.next;
while (tmp != &timeout_list) {
cur = list_get_instance(tmp, awaiter_t, link);
awaiter_t *cur = list_get_instance(tmp, awaiter_t, link);
if (tv_gteq(&cur->expires, &wd->expires))
break;
tmp = tmp->next;
}
list_append(&wd->link, tmp);
}
 
281,93 → 275,146
* its message queue. If the fibril was not active, it is activated and all
* timeouts are unregistered.
*
* @param callid Hash of the incoming call.
* @param call Data of the incoming call.
* @param callid Hash of the incoming call.
* @param call Data of the incoming call.
*
* @return Zero if the call doesn't match any connection.
* One if the call was passed to the respective connection
* fibril.
* @return False if the call doesn't match any connection.
* True if the call was passed to the respective connection fibril.
*
*/
static int route_call(ipc_callid_t callid, ipc_call_t *call)
static bool route_call(ipc_callid_t callid, ipc_call_t *call)
{
connection_t *conn;
msg_t *msg;
link_t *hlp;
unsigned long key;
 
futex_down(&async_futex);
 
key = call->in_phone_hash;
hlp = hash_table_find(&conn_hash_table, &key);
unsigned long key = call->in_phone_hash;
link_t *hlp = hash_table_find(&conn_hash_table, &key);
if (!hlp) {
futex_up(&async_futex);
return 0;
return false;
}
conn = hash_table_get_instance(hlp, connection_t, link);
 
msg = malloc(sizeof(*msg));
connection_t *conn = hash_table_get_instance(hlp, connection_t, link);
msg_t *msg = malloc(sizeof(*msg));
if (!msg) {
futex_up(&async_futex);
return false;
}
msg->callid = callid;
msg->call = *call;
list_append(&msg->link, &conn->msg_queue);
 
if (IPC_GET_METHOD(*call) == IPC_M_PHONE_HUNGUP)
conn->close_callid = callid;
/* If the connection fibril is waiting for an event, activate it */
if (!conn->wdata.active) {
/* If in timeout list, remove it */
if (conn->wdata.inlist) {
conn->wdata.inlist = 0;
conn->wdata.inlist = false;
list_remove(&conn->wdata.link);
}
conn->wdata.active = 1;
conn->wdata.active = true;
fibril_add_ready(conn->wdata.fid);
}
 
futex_up(&async_futex);
return true;
}
 
return 1;
/** Notification fibril.
*
* When a notification arrives, a fibril with this implementing function is
* created. It calls interrupt_received() and does the final cleanup.
*
* @param arg Message structure pointer.
*
* @return Always zero.
*
*/
static int notification_fibril(void *arg)
{
msg_t *msg = (msg_t *) arg;
interrupt_received(msg->callid, &msg->call);
free(msg);
return 0;
}
 
/** Process interrupt notification.
*
* A new fibril is created which would process the notification.
*
* @param callid Hash of the incoming call.
* @param call Data of the incoming call.
*
* @return False if an error occured.
* True if the call was passed to the notification fibril.
*
*/
static bool process_notification(ipc_callid_t callid, ipc_call_t *call)
{
futex_down(&async_futex);
msg_t *msg = malloc(sizeof(*msg));
if (!msg) {
futex_up(&async_futex);
return false;
}
msg->callid = callid;
msg->call = *call;
fid_t fid = fibril_create(notification_fibril, msg);
fibril_add_ready(fid);
futex_up(&async_futex);
return true;
}
 
/** Return new incoming message for the current (fibril-local) connection.
*
* @param call Storage where the incoming call data will be stored.
* @param usecs Timeout in microseconds. Zero denotes no timeout.
* @param call Storage where the incoming call data will be stored.
* @param usecs Timeout in microseconds. Zero denotes no timeout.
*
* @return If no timeout was specified, then a hash of the
* incoming call is returned. If a timeout is specified,
* then a hash of the incoming call is returned unless
* the timeout expires prior to receiving a message. In
* that case zero is returned.
* @return If no timeout was specified, then a hash of the
* incoming call is returned. If a timeout is specified,
* then a hash of the incoming call is returned unless
* the timeout expires prior to receiving a message. In
* that case zero is returned.
*
*/
ipc_callid_t async_get_call_timeout(ipc_call_t *call, suseconds_t usecs)
{
msg_t *msg;
ipc_callid_t callid;
connection_t *conn;
assert(FIBRIL_connection);
assert(FIBRIL_connection);
/* GCC 4.1.0 coughs on FIBRIL_connection-> dereference,
/* Why doing this?
* GCC 4.1.0 coughs on FIBRIL_connection-> dereference.
* GCC 4.1.1 happilly puts the rdhwr instruction in delay slot.
* I would never expect to find so many errors in
* a compiler *($&$(*&$
* I would never expect to find so many errors in
* a compiler.
*/
conn = FIBRIL_connection;
 
connection_t *conn = FIBRIL_connection;
futex_down(&async_futex);
 
if (usecs) {
gettimeofday(&conn->wdata.expires, NULL);
tv_add(&conn->wdata.expires, usecs);
} else {
conn->wdata.inlist = 0;
}
} else
conn->wdata.inlist = false;
/* If nothing in queue, wait until something arrives */
while (list_empty(&conn->msg_queue)) {
if (usecs)
insert_timeout(&conn->wdata);
 
conn->wdata.active = 0;
conn->wdata.active = false;
/*
* Note: the current fibril will be rescheduled either due to a
* timeout or due to an arriving message destined to it. In the
375,13 → 422,14
* case, route_call() will perform the wakeup.
*/
fibril_switch(FIBRIL_TO_MANAGER);
/*
* Futex is up after getting back from async_manager get it
* again.
* Futex is up after getting back from async_manager.
* Get it again.
*/
futex_down(&async_futex);
if (usecs && conn->wdata.timedout &&
list_empty(&conn->msg_queue)) {
if ((usecs) && (conn->wdata.timedout)
&& (list_empty(&conn->msg_queue))) {
/* If we timed out -> exit */
futex_up(&async_futex);
return 0;
388,9 → 436,10
}
}
msg = list_get_instance(conn->msg_queue.next, msg_t, link);
msg_t *msg = list_get_instance(conn->msg_queue.next, msg_t, link);
list_remove(&msg->link);
callid = msg->callid;
ipc_callid_t callid = msg->callid;
*call = msg->call;
free(msg);
402,8 → 451,9
*
* This function is defined as a weak symbol - to be redefined in user code.
*
* @param callid Hash of the incoming call.
* @param call Data of the incoming call.
* @param callid Hash of the incoming call.
* @param call Data of the incoming call.
*
*/
static void default_client_connection(ipc_callid_t callid, ipc_call_t *call)
{
412,8 → 462,11
 
/** Default fibril function that gets called to handle interrupt notifications.
*
* @param callid Hash of the incoming call.
* @param call Data of the incoming call.
* This function is defined as a weak symbol - to be redefined in user code.
*
* @param callid Hash of the incoming call.
* @param call Data of the incoming call.
*
*/
static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call)
{
424,17 → 477,17
* When a new connection arrives, a fibril with this implementing function is
* created. It calls client_connection() and does the final cleanup.
*
* @param arg Connection structure pointer.
* @param arg Connection structure pointer.
*
* @return Always zero.
* @return Always zero.
*
*/
static int connection_fibril(void *arg)
static int connection_fibril(void *arg)
{
unsigned long key;
msg_t *msg;
int close_answered = 0;
 
/* Setup fibril-local connection pointer */
/*
* Setup fibril-local connection pointer and call client_connection().
*
*/
FIBRIL_connection = (connection_t *) arg;
FIBRIL_connection->cfibril(FIBRIL_connection->callid,
&FIBRIL_connection->call);
441,20 → 494,20
/* Remove myself from the connection hash table */
futex_down(&async_futex);
key = FIBRIL_connection->in_phone_hash;
unsigned long key = FIBRIL_connection->in_phone_hash;
hash_table_remove(&conn_hash_table, &key, 1);
futex_up(&async_futex);
/* Answer all remaining messages with EHANGUP */
while (!list_empty(&FIBRIL_connection->msg_queue)) {
msg = list_get_instance(FIBRIL_connection->msg_queue.next,
msg_t, link);
msg_t *msg
= list_get_instance(FIBRIL_connection->msg_queue.next, msg_t, link);
list_remove(&msg->link);
if (msg->callid == FIBRIL_connection->close_callid)
close_answered = 1;
ipc_answer_0(msg->callid, EHANGUP);
free(msg);
}
if (FIBRIL_connection->close_callid)
ipc_answer_0(FIBRIL_connection->close_callid, EOK);
463,43 → 516,45
 
/** Create a new fibril for a new connection.
*
* Creates new fibril for connection, fills in connection structures and inserts
* Create new fibril for connection, fill in connection structures and inserts
* it into the hash table, so that later we can easily do routing of messages to
* particular fibrils.
*
* @param in_phone_hash Identification of the incoming connection.
* @param callid Hash of the opening IPC_M_CONNECT_ME_TO call.
* If callid is zero, the connection was opened by
* accepting the IPC_M_CONNECT_TO_ME call and this function
* is called directly by the server.
* @param call Call data of the opening call.
* @param cfibril Fibril function that should be called upon opening the
* connection.
* @param in_phone_hash Identification of the incoming connection.
* @param callid Hash of the opening IPC_M_CONNECT_ME_TO call.
* If callid is zero, the connection was opened by
* accepting the IPC_M_CONNECT_TO_ME call and this function
* is called directly by the server.
* @param call Call data of the opening call.
* @param cfibril Fibril function that should be called upon opening the
* connection.
*
* @return New fibril id or NULL on failure.
* @return New fibril id or NULL on failure.
*
*/
fid_t async_new_connection(ipcarg_t in_phone_hash, ipc_callid_t callid,
ipc_call_t *call, void (*cfibril)(ipc_callid_t, ipc_call_t *))
{
connection_t *conn;
unsigned long key;
conn = malloc(sizeof(*conn));
connection_t *conn = malloc(sizeof(*conn));
if (!conn) {
if (callid)
ipc_answer_0(callid, ENOMEM);
return NULL;
}
conn->in_phone_hash = in_phone_hash;
list_initialize(&conn->msg_queue);
conn->callid = callid;
conn->close_callid = 0;
conn->close_callid = false;
if (call)
conn->call = *call;
conn->wdata.active = 1; /* We will activate the fibril ASAP */
/* We will activate the fibril ASAP */
conn->wdata.active = true;
conn->cfibril = cfibril;
conn->wdata.fid = fibril_create(connection_fibril, conn);
conn->wdata.fid = fibril_create(connection_fibril, conn);
if (!conn->wdata.fid) {
free(conn);
if (callid)
508,7 → 563,8
}
/* Add connection to the connection hash table */
key = conn->in_phone_hash;
ipcarg_t key = conn->in_phone_hash;
futex_down(&async_futex);
hash_table_insert(&conn_hash_table, &key, &conn->link);
futex_up(&async_futex);
523,8 → 579,8
* If the call has the IPC_M_CONNECT_ME_TO method, a new connection is created.
* Otherwise the call is routed to its connection fibril.
*
* @param callid Hash of the incoming call.
* @param call Data of the incoming call.
* @param callid Hash of the incoming call.
* @param call Data of the incoming call.
*
*/
static void handle_call(ipc_callid_t callid, ipc_call_t *call)
531,9 → 587,7
{
/* Unrouted call - do some default behaviour */
if ((callid & IPC_CALLID_NOTIFICATION)) {
_in_interrupt_handler = 1;
(*interrupt_received)(callid, call);
_in_interrupt_handler = 0;
process_notification(callid, call);
return;
}
557,47 → 611,44
static void handle_expired_timeouts(void)
{
struct timeval tv;
awaiter_t *waiter;
link_t *cur;
 
gettimeofday(&tv, NULL);
futex_down(&async_futex);
 
cur = timeout_list.next;
link_t *cur = timeout_list.next;
while (cur != &timeout_list) {
waiter = list_get_instance(cur, awaiter_t, link);
awaiter_t *waiter = list_get_instance(cur, awaiter_t, link);
if (tv_gt(&waiter->expires, &tv))
break;
cur = cur->next;
list_remove(&waiter->link);
waiter->inlist = 0;
waiter->timedout = 1;
waiter->inlist = false;
waiter->timedout = true;
/*
* Redundant condition?
* The fibril should not be active when it gets here.
* Redundant condition?
* The fibril should not be active when it gets here.
*/
if (!waiter->active) {
waiter->active = 1;
waiter->active = true;
fibril_add_ready(waiter->fid);
}
}
 
futex_up(&async_futex);
}
 
/** Endless loop dispatching incoming calls and answers.
*
* @return Never returns.
* @return Never returns.
*
*/
static int async_manager_worker(void)
{
ipc_call_t call;
ipc_callid_t callid;
int timeout;
awaiter_t *waiter;
struct timeval tv;
 
while (1) {
while (true) {
if (fibril_switch(FIBRIL_FROM_MANAGER)) {
futex_up(&async_futex);
/*
606,11 → 657,17
*/
continue;
}
futex_down(&async_futex);
suseconds_t timeout;
if (!list_empty(&timeout_list)) {
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);
if (tv_gteq(&tv, &waiter->expires)) {
futex_up(&async_futex);
handle_expired_timeouts();
619,19 → 676,21
timeout = tv_sub(&waiter->expires, &tv);
} else
timeout = SYNCH_NO_TIMEOUT;
futex_up(&async_futex);
 
callid = ipc_wait_cycle(&call, timeout, SYNCH_FLAGS_NONE);
 
ipc_call_t call;
ipc_callid_t callid
= ipc_wait_cycle(&call, timeout, SYNCH_FLAGS_NONE);
if (!callid) {
handle_expired_timeouts();
continue;
}
 
if (callid & IPC_CALLID_ANSWERED) {
if (callid & IPC_CALLID_ANSWERED)
continue;
}
 
handle_call(callid, &call);
}
639,16 → 698,17
}
 
/** Function to start async_manager as a standalone fibril.
*
*
* When more kernel threads are used, one async manager should exist per thread.
*
* @param arg Unused.
* @param arg Unused.
* @return Never returns.
*
* @return Never returns.
*/
static int async_manager_fibril(void *arg)
{
futex_up(&async_futex);
/*
* async_futex is always locked when entering manager
*/
660,9 → 720,7
/** Add one manager to manager list. */
void async_create_manager(void)
{
fid_t fid;
 
fid = fibril_create(async_manager_fibril, NULL);
fid_t fid = fibril_create(async_manager_fibril, NULL);
fibril_add_manager(fid);
}
 
674,7 → 732,7
 
/** Initialize the async framework.
*
* @return Zero on success or an error code.
* @return Zero on success or an error code.
*/
int _async_init(void)
{
694,30 → 752,33
*
* Notify the fibril which is waiting for this message that it has arrived.
*
* @param private Pointer to the asynchronous message record.
* @param retval Value returned in the answer.
* @param data Call data of the answer.
* @param arg Pointer to the asynchronous message record.
* @param retval Value returned in the answer.
* @param data Call data of the answer.
*/
static void reply_received(void *private, int retval, ipc_call_t *data)
static void reply_received(void *arg, int retval, ipc_call_t *data)
{
amsg_t *msg = (amsg_t *) private;
 
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)
*msg->dataptr = *data;
 
*msg->dataptr = *data;
write_barrier();
/* Remove message from timeout list */
if (msg->wdata.inlist)
list_remove(&msg->wdata.link);
msg->done = 1;
msg->done = true;
if (!msg->wdata.active) {
msg->wdata.active = 1;
msg->wdata.active = true;
fibril_add_ready(msg->wdata.fid);
}
futex_up(&async_futex);
}
 
726,31 → 787,34
* The return value can be used as input for async_wait() to wait for
* completion.
*
* @param phoneid Handle of the phone that will be used for the send.
* @param method Service-defined method.
* @param arg1 Service-defined payload argument.
* @param arg2 Service-defined payload argument.
* @param arg3 Service-defined payload argument.
* @param arg4 Service-defined payload argument.
* @param dataptr If non-NULL, storage where the reply data will be
* stored.
* @param phoneid Handle of the phone that will be used for the send.
* @param method Service-defined method.
* @param arg1 Service-defined payload argument.
* @param arg2 Service-defined payload argument.
* @param arg3 Service-defined payload argument.
* @param arg4 Service-defined payload argument.
* @param dataptr If non-NULL, storage where the reply data will be
* stored.
*
* @return Hash of the sent message.
* @return Hash of the sent message or 0 on error.
*
*/
aid_t async_send_fast(int phoneid, ipcarg_t method, ipcarg_t arg1,
ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4, ipc_call_t *dataptr)
{
amsg_t *msg;
amsg_t *msg = malloc(sizeof(*msg));
msg = malloc(sizeof(*msg));
msg->done = 0;
if (!msg)
return 0;
msg->done = false;
msg->dataptr = dataptr;
/* We may sleep in the next method, but it will use its own mechanism */
msg->wdata.active = 1;
msg->wdata.active = true;
ipc_call_async_4(phoneid, method, arg1, arg2, arg3, arg4, msg,
reply_received, !_in_interrupt_handler);
reply_received, true);
return (aid_t) msg;
}
760,33 → 824,36
* The return value can be used as input for async_wait() to wait for
* completion.
*
* @param phoneid Handle of the phone that will be used for the send.
* @param method Service-defined method.
* @param arg1 Service-defined payload argument.
* @param arg2 Service-defined payload argument.
* @param arg3 Service-defined payload argument.
* @param arg4 Service-defined payload argument.
* @param arg5 Service-defined payload argument.
* @param dataptr If non-NULL, storage where the reply data will be
* stored.
* @param phoneid Handle of the phone that will be used for the send.
* @param method Service-defined method.
* @param arg1 Service-defined payload argument.
* @param arg2 Service-defined payload argument.
* @param arg3 Service-defined payload argument.
* @param arg4 Service-defined payload argument.
* @param arg5 Service-defined payload argument.
* @param dataptr If non-NULL, storage where the reply data will be
* stored.
*
* @return Hash of the sent message.
* @return Hash of the sent message or 0 on error.
*
*/
aid_t async_send_slow(int phoneid, ipcarg_t method, ipcarg_t arg1,
ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4, ipcarg_t arg5,
ipc_call_t *dataptr)
{
amsg_t *msg;
amsg_t *msg = malloc(sizeof(*msg));
msg = malloc(sizeof(*msg));
msg->done = 0;
if (!msg)
return 0;
msg->done = false;
msg->dataptr = dataptr;
/* We may sleep in next method, but it will use its own mechanism */
msg->wdata.active = 1;
msg->wdata.active = true;
ipc_call_async_5(phoneid, method, arg1, arg2, arg3, arg4, arg5, msg,
reply_received, !_in_interrupt_handler);
reply_received, true);
return (aid_t) msg;
}
793,74 → 860,82
 
/** Wait for a message sent by the async framework.
*
* @param amsgid Hash of the message to wait for.
* @param retval Pointer to storage where the retval of the answer will
* be stored.
* @param amsgid Hash of the message to wait for.
* @param retval Pointer to storage where the retval of the answer will
* be stored.
*
*/
void async_wait_for(aid_t amsgid, ipcarg_t *retval)
{
amsg_t *msg = (amsg_t *) amsgid;
 
futex_down(&async_futex);
if (msg->done) {
futex_up(&async_futex);
goto done;
}
 
msg->wdata.fid = fibril_get_id();
msg->wdata.active = 0;
msg->wdata.inlist = 0;
msg->wdata.active = false;
msg->wdata.inlist = false;
/* Leave the async_futex locked when entering this function */
fibril_switch(FIBRIL_TO_MANAGER);
/* futex is up automatically after fibril_switch...*/
/* Futex is up automatically after fibril_switch */
done:
if (retval)
*retval = msg->retval;
free(msg);
}
 
/** Wait for a message sent by the async framework, timeout variant.
*
* @param amsgid Hash of the message to wait for.
* @param retval Pointer to storage where the retval of the answer will
* be stored.
* @param timeout Timeout in microseconds.
* @param amsgid Hash of the message to wait for.
* @param retval Pointer to storage where the retval of the answer will
* be stored.
* @param timeout Timeout in microseconds.
*
* @return Zero on success, ETIMEOUT if the timeout has expired.
* @return Zero on success, ETIMEOUT if the timeout has expired.
*
*/
int async_wait_timeout(aid_t amsgid, ipcarg_t *retval, suseconds_t timeout)
{
amsg_t *msg = (amsg_t *) amsgid;
 
/* TODO: Let it go through the event read at least once */
if (timeout < 0)
return ETIMEOUT;
 
futex_down(&async_futex);
if (msg->done) {
futex_up(&async_futex);
goto done;
}
 
gettimeofday(&msg->wdata.expires, NULL);
tv_add(&msg->wdata.expires, timeout);
 
msg->wdata.fid = fibril_get_id();
msg->wdata.active = 0;
msg->wdata.active = false;
insert_timeout(&msg->wdata);
 
/* Leave the async_futex locked when entering this function */
fibril_switch(FIBRIL_TO_MANAGER);
/* futex is up automatically after fibril_switch...*/
 
/* Futex is up automatically after fibril_switch */
if (!msg->done)
return ETIMEOUT;
 
done:
if (retval)
*retval = msg->retval;
free(msg);
 
return 0;
}
 
868,33 → 943,38
*
* The current fibril is suspended but the thread continues to execute.
*
* @param timeout Duration of the wait in microseconds.
* @param timeout Duration of the wait in microseconds.
*
*/
void async_usleep(suseconds_t timeout)
{
amsg_t *msg;
amsg_t *msg = malloc(sizeof(*msg));
msg = malloc(sizeof(*msg));
if (!msg)
return;
msg->wdata.fid = fibril_get_id();
msg->wdata.active = 0;
msg->wdata.active = false;
gettimeofday(&msg->wdata.expires, NULL);
tv_add(&msg->wdata.expires, timeout);
futex_down(&async_futex);
insert_timeout(&msg->wdata);
/* Leave the async_futex locked when entering this function */
fibril_switch(FIBRIL_TO_MANAGER);
/* futex is up automatically after fibril_switch()...*/
/* Futex is up automatically after fibril_switch() */
free(msg);
}
 
/** Setter for client_connection function pointer.
*
* @param conn Function that will implement a new connection fibril.
* @param conn Function that will implement a new connection fibril.
*
*/
void async_set_client_connection(async_client_conn_t conn)
{
903,12 → 983,12
 
/** Setter for interrupt_received function pointer.
*
* @param conn Function that will implement a new interrupt
* notification fibril.
* @param intr Function that will implement a new interrupt
* notification fibril.
*/
void async_set_interrupt_received(async_client_conn_t conn)
void async_set_interrupt_received(async_client_conn_t intr)
{
interrupt_received = conn;
interrupt_received = intr;
}
 
/** Pseudo-synchronous message sending - fast version.
918,18 → 998,20
* This function can only transfer 4 register payload arguments. For
* transferring more arguments, see the slower async_req_slow().
*
* @param phoneid Hash of the phone through which to make the call.
* @param method Method of the call.
* @param arg1 Service-defined payload argument.
* @param arg2 Service-defined payload argument.
* @param arg3 Service-defined payload argument.
* @param arg4 Service-defined payload argument.
* @param r1 If non-NULL, storage for the 1st reply argument.
* @param r2 If non-NULL, storage for the 2nd reply argument.
* @param r3 If non-NULL, storage for the 3rd reply argument.
* @param r4 If non-NULL, storage for the 4th reply argument.
* @param r5 If non-NULL, storage for the 5th reply argument.
* @return Return code of the reply or a negative error code.
* @param phoneid Hash of the phone through which to make the call.
* @param method Method of the call.
* @param arg1 Service-defined payload argument.
* @param arg2 Service-defined payload argument.
* @param arg3 Service-defined payload argument.
* @param arg4 Service-defined payload argument.
* @param r1 If non-NULL, storage for the 1st reply argument.
* @param r2 If non-NULL, storage for the 2nd reply argument.
* @param r3 If non-NULL, storage for the 3rd reply argument.
* @param r4 If non-NULL, storage for the 4th reply argument.
* @param r5 If non-NULL, storage for the 5th reply argument.
*
* @return Return code of the reply or a negative error code.
*
*/
ipcarg_t async_req_fast(int phoneid, ipcarg_t method, ipcarg_t arg1,
ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4, ipcarg_t *r1, ipcarg_t *r2,
936,21 → 1018,27
ipcarg_t *r3, ipcarg_t *r4, ipcarg_t *r5)
{
ipc_call_t result;
ipcarg_t rc;
 
aid_t eid = async_send_4(phoneid, method, arg1, arg2, arg3, arg4,
&result);
ipcarg_t rc;
async_wait_for(eid, &rc);
if (r1)
if (r1)
*r1 = IPC_GET_ARG1(result);
if (r2)
*r2 = IPC_GET_ARG2(result);
if (r3)
*r3 = IPC_GET_ARG3(result);
if (r4)
*r4 = IPC_GET_ARG4(result);
if (r5)
*r5 = IPC_GET_ARG5(result);
return rc;
}
 
958,19 → 1046,21
*
* Send message asynchronously and return only after the reply arrives.
*
* @param phoneid Hash of the phone through which to make the call.
* @param method Method of the call.
* @param arg1 Service-defined payload argument.
* @param arg2 Service-defined payload argument.
* @param arg3 Service-defined payload argument.
* @param arg4 Service-defined payload argument.
* @param arg5 Service-defined payload argument.
* @param r1 If non-NULL, storage for the 1st reply argument.
* @param r2 If non-NULL, storage for the 2nd reply argument.
* @param r3 If non-NULL, storage for the 3rd reply argument.
* @param r4 If non-NULL, storage for the 4th reply argument.
* @param r5 If non-NULL, storage for the 5th reply argument.
* @return Return code of the reply or a negative error code.
* @param phoneid Hash of the phone through which to make the call.
* @param method Method of the call.
* @param arg1 Service-defined payload argument.
* @param arg2 Service-defined payload argument.
* @param arg3 Service-defined payload argument.
* @param arg4 Service-defined payload argument.
* @param arg5 Service-defined payload argument.
* @param r1 If non-NULL, storage for the 1st reply argument.
* @param r2 If non-NULL, storage for the 2nd reply argument.
* @param r3 If non-NULL, storage for the 3rd reply argument.
* @param r4 If non-NULL, storage for the 4th reply argument.
* @param r5 If non-NULL, storage for the 5th reply argument.
*
* @return Return code of the reply or a negative error code.
*
*/
ipcarg_t async_req_slow(int phoneid, ipcarg_t method, ipcarg_t arg1,
ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4, ipcarg_t arg5, ipcarg_t *r1,
977,21 → 1067,27
ipcarg_t *r2, ipcarg_t *r3, ipcarg_t *r4, ipcarg_t *r5)
{
ipc_call_t result;
ipcarg_t rc;
 
aid_t eid = async_send_5(phoneid, method, arg1, arg2, arg3, arg4, arg5,
&result);
ipcarg_t rc;
async_wait_for(eid, &rc);
if (r1)
if (r1)
*r1 = IPC_GET_ARG1(result);
if (r2)
*r2 = IPC_GET_ARG2(result);
if (r3)
*r3 = IPC_GET_ARG3(result);
if (r4)
*r4 = IPC_GET_ARG4(result);
if (r5)
*r5 = IPC_GET_ARG5(result);
return rc;
}
 
/branches/network/uspace/lib/libc/generic/vfs/vfs.c
76,7 → 76,7
futex_up(&cwd_futex);
return NULL;
}
str_ncpy(ncwd_path_nc, cwd_path, cwd_size + 1 + size + 1);
str_cpy(ncwd_path_nc, cwd_size + 1 + size + 1, cwd_path);
ncwd_path_nc[cwd_size] = '/';
ncwd_path_nc[cwd_size + 1] = '\0';
} else {
87,7 → 87,7
}
ncwd_path_nc[0] = '\0';
}
strcat(ncwd_path_nc, path);
str_append(ncwd_path_nc, cwd_size + 1 + size + 1, path);
ncwd_path = canonify(ncwd_path_nc, retlen);
if (!ncwd_path) {
futex_up(&cwd_futex);
99,7 → 99,7
* the address in ncwd_path need not be the same as ncwd_path_nc, even
* though they both point into the same dynamically allocated buffer.
*/
ncwd_path = strdup(ncwd_path);
ncwd_path = str_dup(ncwd_path);
free(ncwd_path_nc);
if (!ncwd_path) {
futex_up(&cwd_futex);
155,7 → 155,7
}
 
int mount(const char *fs_name, const char *mp, const char *dev,
const unsigned int flags)
const char *opts, const unsigned int flags)
{
int res;
ipcarg_t rc;
185,6 → 185,15
return (int) rc;
}
rc = ipc_data_write_start(vfs_phone, (void *) opts, str_size(opts));
if (rc != EOK) {
async_wait_for(req, NULL);
async_serialize_end();
futex_up(&vfs_phone_futex);
free(mpa);
return (int) rc;
}
 
rc = ipc_data_write_start(vfs_phone, (void *) fs_name, str_size(fs_name));
if (rc != EOK) {
async_wait_for(req, NULL);
193,6 → 202,16
free(mpa);
return (int) rc;
}
 
/* Ask VFS whether it likes fs_name. */
rc = async_req_0_0(vfs_phone, IPC_M_PING);
if (rc != EOK) {
async_wait_for(req, NULL);
async_serialize_end();
futex_up(&vfs_phone_futex);
free(mpa);
return (int) rc;
}
async_wait_for(req, &rc);
async_serialize_end();
534,7 → 553,7
futex_up(&cwd_futex);
return NULL;
}
str_ncpy(buf, cwd_path, size);
str_cpy(buf, size, cwd_path);
futex_up(&cwd_futex);
return buf;
}
/branches/network/uspace/lib/libc/generic/io/io.c
38,6 → 38,7
#include <io/io.h>
#include <string.h>
#include <errno.h>
#include <console.h>
 
const static char nl = '\n';
 
49,8 → 50,9
return putnchars("(NULL)", 6);
for (count = 0; str[count] != 0; count++);
if (write_stdout((void *) str, count) == count) {
if (write_stdout(&nl, 1) == 1)
if (console_write((void *) str, count) == count) {
if (console_write(&nl, 1) == 1)
return 0;
}
64,7 → 66,7
*/
int putnchars(const char *buf, size_t count)
{
if (write_stdout((void *) buf, count) == count)
if (console_write((void *) buf, count) == count)
return 0;
return EOF;
81,7 → 83,7
return putnchars("(NULL)", 6);
 
for (count = 0; str[count] != 0; count++);
if (write_stdout((void *) str, count) == count)
if (console_write((void *) str, count) == count)
return 0;
return EOF;
96,7 → 98,7
if (chr_encode(c, buf, &offs, STR_BOUNDS(1)) != EOK)
return EOF;
 
if (write_stdout((void *) buf, offs) == offs)
if (console_write((void *) buf, offs) == offs)
return c;
 
return EOF;
105,8 → 107,8
int getchar(void)
{
unsigned char c;
 
flush_stdout();
console_flush();
if (read_stdin((void *) &c, 1) == 1)
return c;
115,8 → 117,10
 
int fflush(FILE *f)
{
/* Dummy implementation */
(void) f;
return flush_stdout();
console_flush();
return 0;
}
 
/** @}
/branches/network/uspace/lib/libc/generic/io/vprintf.c
38,6 → 38,7
#include <io/printf_core.h>
#include <futex.h>
#include <async.h>
#include <console.h>
 
static atomic_t printf_futex = FUTEX_INITIALIZER;
 
50,7 → 51,7
while (offset < size) {
prev = offset;
str_decode(str, &offset, size);
write_stdout(str + prev, offset - prev);
console_write(str + prev, offset - prev);
chars++;
}
67,7 → 68,7
while (offset < size) {
boff = 0;
chr_encode(str[chars], buf, &boff, 4);
write_stdout(buf, boff);
console_write(buf, boff);
chars++;
offset += sizeof(wchar_t);
}
/branches/network/uspace/lib/libc/generic/io/stream.c
49,62 → 49,28
#include <async.h>
#include <sys/types.h>
 
ssize_t write_stderr(const void *buf, size_t count)
{
return count;
}
 
ssize_t read_stdin(void *buf, size_t count)
{
int cons_phone = console_phone_get(false);
 
int cons_phone = console_open(false);
if (cons_phone >= 0) {
kbd_event_t ev;
int rc;
size_t i = 0;
while (i < count) {
do {
rc = kbd_get_event(&ev);
if (rc < 0) return -1;
} while (ev.c == 0 || ev.type == KE_RELEASE);
 
((char *) buf)[i++] = ev.c;
}
return i;
} else {
} else
return -1;
}
}
 
ssize_t write_stdout(const void *buf, size_t count)
{
int cons_phone = console_phone_get(false);
int left, rc;
 
if (cons_phone >= 0) {
int i;
 
left = count;
while (left > 0) {
rc = console_write(buf, left);
if (rc < 0)
break;
buf += rc;
left -= rc;
}
 
return count;
} else
return __SYSCALL3(SYS_KLOG, 1, (sysarg_t) buf, count);
}
 
int flush_stdout(void)
{
console_flush();
return 0;
}
 
void klog_update(void)
{
(void) __SYSCALL3(SYS_KLOG, 1, NULL, 0);
/branches/network/uspace/lib/libc/arch/ia64/include/ddi.h
53,7 → 53,7
{
uintptr_t prt = (uintptr_t) port;
 
*((uint8_t *)(IA64_IOSPACE_ADDRESS +
*((ioport8_t *)(IA64_IOSPACE_ADDRESS +
((prt & 0xfff) | ((prt >> 2) << 12)))) = v;
 
asm volatile ("mf\n" ::: "memory");
63,7 → 63,7
{
uintptr_t prt = (uintptr_t) port;
 
*((uint16_t *)(IA64_IOSPACE_ADDRESS +
*((ioport16_t *)(IA64_IOSPACE_ADDRESS +
((prt & 0xfff) | ((prt >> 2) << 12)))) = v;
 
asm volatile ("mf\n" ::: "memory");
73,7 → 73,7
{
uintptr_t prt = (uintptr_t) port;
 
*((uint32_t *)(IA64_IOSPACE_ADDRESS +
*((ioport32_t *)(IA64_IOSPACE_ADDRESS +
((prt & 0xfff) | ((prt >> 2) << 12)))) = v;
 
asm volatile ("mf\n" ::: "memory");
85,7 → 85,7
 
asm volatile ("mf\n" ::: "memory");
 
return *((uint8_t *)(IA64_IOSPACE_ADDRESS +
return *((ioport8_t *)(IA64_IOSPACE_ADDRESS +
((prt & 0xfff) | ((prt >> 2) << 12))));
}
 
95,7 → 95,7
 
asm volatile ("mf\n" ::: "memory");
 
return *((uint16_t *)(IA64_IOSPACE_ADDRESS +
return *((ioport16_t *)(IA64_IOSPACE_ADDRESS +
((prt & 0xfff) | ((prt >> 2) << 12))));
}
 
105,7 → 105,7
 
asm volatile ("mf\n" ::: "memory");
 
return *((uint32_t *)(IA64_IOSPACE_ADDRESS +
return *((ioport32_t *)(IA64_IOSPACE_ADDRESS +
((prt & 0xfff) | ((prt >> 2) << 12))));
}