libc.obj: implement console output via SHELL (#354)
Adding console I/O via the `SHELL`. Demonstration of [http_tcp_demo.c](https://git.kolibrios.org/KolibriOS/kolibrios/src/branch/main/programs/develop/ktcc/libc.obj/samples/http_tcp_demo.c): <video src="attachments/847d7d19-3d67-480d-80c8-6d678af61a43" title="Запись экрана от 2026-03-07 13-55-50.mp4" controls></video> - [x] output - [x] multithread - [x] add mutex - [x] multithread tests Reviewed-on: #354 Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com> Reviewed-by: Kiril Lipatov <lipatov.kiril@gmail.com> Co-authored-by: Egor00f <y.yarin@inbox.ru>
This commit was merged in pull request #354.
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
CC = kos32-tcc
|
||||
AR = ar
|
||||
CFLAGS = -c -I../../libc.obj/include
|
||||
CFLAGS = -c -I$(LIBC_INCLUDE)
|
||||
|
||||
LIBC_INCLUDE = ../../libc.obj/include
|
||||
|
||||
LIB = libshell.a
|
||||
|
||||
@@ -14,7 +16,8 @@ OBJS = \
|
||||
shell_init.o \
|
||||
shell_gets.o \
|
||||
shell_printf.o \
|
||||
shell_putc.o
|
||||
shell_putc.o \
|
||||
shell_write_string.o
|
||||
|
||||
$(LIB): $(OBJS)
|
||||
$(AR) -crs $@ $(OBJS)
|
||||
@@ -23,4 +26,16 @@ $(LIB): $(OBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJS) $(LIB)
|
||||
rm -rf $(OBJS) $(LIB)
|
||||
|
||||
|
||||
shell_cls.o: shell_cls.c $(LIBC_INCLUDE)/shell_api.h $(LIBC_INCLUDE)/sys/ksys.h
|
||||
shell_get_pid.o: shell_get_pid.c $(LIBC_INCLUDE)/shell_api.h $(LIBC_INCLUDE)/string.h
|
||||
shell_getc.o: shell_getc.c $(LIBC_INCLUDE)/shell_api.h
|
||||
shell_gets.o: shell_gets.c $(LIBC_INCLUDE)/shell_api.h $(LIBC_INCLUDE)/string.h
|
||||
shell_init.o: shell_init.c $(LIBC_INCLUDE)/shell_api.h $(LIBC_INCLUDE)/sys/ksys.h $(LIBC_INCLUDE)/string.h $(LIBC_INCLUDE)/stdio.h $(LIBC_INCLUDE)/stdlib.h
|
||||
shell_ping.o: shell_ping.c $(LIBC_INCLUDE)/shell_api.h $(LIBC_INCLUDE)/sys/ksys.h
|
||||
shell_printf.o: shell_printf.c $(LIBC_INCLUDE)/shell_api.h $(LIBC_INCLUDE)/stdio.h
|
||||
shell_putc.o: shell_putc.c $(LIBC_INCLUDE)/shell_api.h
|
||||
shell_puts.o: shell_puts.c $(LIBC_INCLUDE)/shell_api.h $(LIBC_INCLUDE)/string.h
|
||||
shell_write_string.o: shell_write_string.c $(LIBC_INCLUDE)/shell_api.h $(LIBC_INCLUDE)/string.h
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
void shell_cls()
|
||||
{
|
||||
__shell_init();
|
||||
*__shell_shm = SHELL_CLS;
|
||||
__SHELL_WAIT();
|
||||
}
|
||||
if (__shell_is_init == __SHELL_INIT_OK)
|
||||
{
|
||||
*__shell_shm = SHELL_CLS;
|
||||
__SHELL_WAIT();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
|
||||
void shell_exit()
|
||||
{
|
||||
if(__shell_is_init){
|
||||
if (__shell_is_init == __SHELL_INIT_OK)
|
||||
{
|
||||
*__shell_shm = SHELL_EXIT;
|
||||
__SHELL_WAIT();
|
||||
_ksys_shm_close(__shell_shm_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,15 @@
|
||||
|
||||
unsigned shell_get_pid()
|
||||
{
|
||||
unsigned pid;
|
||||
unsigned pid = 0;
|
||||
|
||||
__shell_init();
|
||||
*__shell_shm = SHELL_PID;
|
||||
__SHELL_WAIT();
|
||||
memcpy(&pid, __shell_shm+1, sizeof(unsigned));
|
||||
if (__shell_is_init == __SHELL_INIT_OK)
|
||||
{
|
||||
*__shell_shm = SHELL_PID;
|
||||
__SHELL_WAIT();
|
||||
memcpy(&pid, __shell_shm + 1, sizeof(unsigned));
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
#include "shell_api.h"
|
||||
#include <shell_api.h>
|
||||
|
||||
char shell_getc()
|
||||
{
|
||||
__shell_init();
|
||||
*__shell_shm = SHELL_GETC;
|
||||
__SHELL_WAIT();
|
||||
return *(__shell_shm+1);
|
||||
}
|
||||
|
||||
if (__shell_is_init == __SHELL_INIT_OK)
|
||||
{
|
||||
*__shell_shm = SHELL_GETC;
|
||||
__SHELL_WAIT();
|
||||
|
||||
return *(__shell_shm + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,12 @@
|
||||
void shell_gets(char *str, int n)
|
||||
{
|
||||
__shell_init();
|
||||
*__shell_shm = SHELL_GETS;
|
||||
__SHELL_WAIT();
|
||||
strncpy(str, __shell_shm+1, n);
|
||||
|
||||
if (__shell_is_init == __SHELL_INIT_OK)
|
||||
{
|
||||
*__shell_shm = SHELL_GETS;
|
||||
__SHELL_WAIT();
|
||||
|
||||
strncpy(str, __shell_shm + 1, n);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,40 +5,63 @@
|
||||
#include <shell_api.h>
|
||||
|
||||
char app_name[13];
|
||||
char __shell_shm_name[32];
|
||||
char*__shell_shm=NULL;
|
||||
int __shell_is_init=0;
|
||||
char __shell_shm_name[32];
|
||||
char *__shell_shm = NULL;
|
||||
enum __SHELL_INIT_STATE __shell_is_init = __SHELL_NOT_LOADED;
|
||||
|
||||
int __shell_shm_init()
|
||||
{
|
||||
__shell_is_init=1;
|
||||
ksys_thread_t *proc_info = (ksys_thread_t*)malloc(sizeof(ksys_thread_t));
|
||||
if(proc_info == NULL){
|
||||
return -1;
|
||||
}
|
||||
__shell_is_init = __SHELL_LOADING;
|
||||
ksys_thread_t proc_info;
|
||||
unsigned PID;
|
||||
|
||||
_ksys_thread_info(proc_info, -1);
|
||||
PID = proc_info->pid;
|
||||
strncpy(app_name, proc_info->name, 12);
|
||||
free(proc_info);
|
||||
_ksys_thread_info(&proc_info, -1);
|
||||
PID = proc_info.pid;
|
||||
strncpy(app_name, (&proc_info)->name, 12);
|
||||
|
||||
itoa(PID, __shell_shm_name);
|
||||
strcat(__shell_shm_name, "-SHELL");
|
||||
return _ksys_shm_open(__shell_shm_name, KSYS_SHM_OPEN_ALWAYS | KSYS_SHM_WRITE, SHELL_SHM_MAX, &__shell_shm);
|
||||
|
||||
return _ksys_shm_open(__shell_shm_name, KSYS_SHM_OPEN_ALWAYS | KSYS_SHM_WRITE, SHELL_SHM_MAX, &__shell_shm);
|
||||
}
|
||||
|
||||
void __shell_init()
|
||||
{
|
||||
if(!__shell_is_init){
|
||||
if(__shell_shm_init()){
|
||||
debug_printf("%s: shell problems detected!\n", app_name);
|
||||
_ksys_exit();
|
||||
switch (__shell_is_init)
|
||||
{
|
||||
case __SHELL_NOT_LOADED:
|
||||
if (__shell_shm_init())
|
||||
{
|
||||
debug_printf("%s: shell problems detected!\n", app_name);
|
||||
goto __shell_init_err;
|
||||
}
|
||||
|
||||
if(!shell_ping()){
|
||||
debug_printf("%s: no shell found!\n", app_name);
|
||||
_ksys_exit();
|
||||
if (!shell_ping())
|
||||
{
|
||||
goto __shell_init_err;
|
||||
}
|
||||
|
||||
__shell_is_init = __SHELL_INIT_OK; // The shell is being pinged, so it's working.
|
||||
break;
|
||||
case __SHELL_LOADING:
|
||||
while (__shell_is_init == __SHELL_LOADING)
|
||||
{
|
||||
_ksys_thread_yield();
|
||||
}
|
||||
case __SHELL_INIT_OK:
|
||||
if (!shell_ping())
|
||||
{
|
||||
goto __shell_init_err;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
__shell_init_err:
|
||||
__shell_is_init = __SHELL_INIT_FAILED;
|
||||
shell_exit();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,26 @@
|
||||
#include <shell_api.h>
|
||||
#include <sys/ksys.h>
|
||||
#include <sys/ksys.h>
|
||||
|
||||
#define SHELL_PING_TIMEOUT 10 // 0.1 sec
|
||||
#define SHELL_PING_MIN_DELAY 1
|
||||
|
||||
int shell_ping()
|
||||
{
|
||||
__shell_init();
|
||||
*__shell_shm = SHELL_PING;
|
||||
_ksys_delay(10);
|
||||
if(*__shell_shm==SHELL_OK){
|
||||
return 1;
|
||||
|
||||
_ksys_thread_yield(); // hope shell is fast enough
|
||||
|
||||
size_t i = 0;
|
||||
while (*__shell_shm != SHELL_OK)
|
||||
{
|
||||
if (i > (SHELL_PING_TIMEOUT / SHELL_PING_MIN_DELAY))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
i++;
|
||||
_ksys_delay(SHELL_PING_MIN_DELAY);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#include <shell_api.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void shell_printf(const char *format,...)
|
||||
void shell_printf(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, format);
|
||||
*__shell_shm=SHELL_PUTS;
|
||||
vsnprintf(__shell_shm+1, SHELL_SHM_MAX, format, ap);
|
||||
va_start(ap, format);
|
||||
vsnprintf(__shell_shm + 1, SHELL_SHM_MAX, format, ap);
|
||||
*__shell_shm = SHELL_PUTS;
|
||||
va_end(ap);
|
||||
__SHELL_WAIT();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
void shell_putc(char c)
|
||||
{
|
||||
__shell_init();
|
||||
*__shell_shm = SHELL_PUTC;
|
||||
*(__shell_shm+1) = c;
|
||||
__SHELL_WAIT();
|
||||
|
||||
if (__shell_is_init == __SHELL_INIT_OK)
|
||||
{
|
||||
*(__shell_shm + 1) = c;
|
||||
*__shell_shm = SHELL_PUTC;
|
||||
__SHELL_WAIT();
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,5 @@
|
||||
|
||||
void shell_puts(const char *str)
|
||||
{
|
||||
__shell_init();
|
||||
*__shell_shm = SHELL_PUTS;
|
||||
strcpy(__shell_shm+1, str);
|
||||
__SHELL_WAIT();
|
||||
}
|
||||
shell_write_string(str, strlen(str));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
#include <shell_api.h>
|
||||
#include <string.h>
|
||||
|
||||
void shell_write_string(const char *s, size_t len)
|
||||
{
|
||||
__shell_init();
|
||||
if (__shell_is_init == __SHELL_INIT_OK)
|
||||
{
|
||||
if (len > SHELL_SHM_MAX - 1)
|
||||
{
|
||||
shell_write_string(s, SHELL_SHM_MAX - 1); // Outputs as much as it can.
|
||||
shell_write_string(s + (SHELL_SHM_MAX - 1), len - (SHELL_SHM_MAX - 1)); // Outputs the rest.
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(__shell_shm, 0, SHELL_SHM_MAX); // without int shell show \t, \n, lose chars and other trash
|
||||
memcpy(__shell_shm + 1, s, len);
|
||||
*__shell_shm = SHELL_PUTS;
|
||||
__SHELL_WAIT();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,12 @@
|
||||
|
||||
#include <sys/ksys.h>
|
||||
|
||||
#ifdef _BUILD_LIBC
|
||||
#define __EXTERN
|
||||
#else
|
||||
#define __EXTERN extern
|
||||
#endif
|
||||
|
||||
#define SHELL_OK 0
|
||||
#define SHELL_EXIT 1
|
||||
#define SHELL_PUTC 2
|
||||
@@ -15,25 +21,35 @@
|
||||
|
||||
#define SHELL_SHM_MAX 1024 * 16
|
||||
|
||||
extern char __shell_shm_name[32];
|
||||
extern char* __shell_shm;
|
||||
extern int __shell_is_init;
|
||||
extern void __shell_init();
|
||||
enum __SHELL_INIT_STATE {
|
||||
__SHELL_NOT_LOADED = 0, // not try init shell before
|
||||
__SHELL_LOADING = 1, // in progress
|
||||
__SHELL_INIT_OK = 2, // ok
|
||||
__SHELL_INIT_FAILED = 3 // fail init shell
|
||||
};
|
||||
|
||||
#define __SHELL_WAIT() \
|
||||
while (*__shell_shm) \
|
||||
_ksys_delay(5)
|
||||
__EXTERN char __shell_shm_name[32];
|
||||
__EXTERN char* __shell_shm;
|
||||
__EXTERN enum __SHELL_INIT_STATE __shell_is_init;
|
||||
__EXTERN void __shell_init();
|
||||
|
||||
extern int shell_ping();
|
||||
extern unsigned shell_get_pid();
|
||||
extern void shell_exit();
|
||||
#define __SHELL_WAIT() \
|
||||
do { \
|
||||
_ksys_thread_yield(); \
|
||||
} while (*__shell_shm);
|
||||
|
||||
extern char shell_getc();
|
||||
extern void shell_gets(char* str, int n);
|
||||
__EXTERN int shell_ping();
|
||||
__EXTERN unsigned shell_get_pid();
|
||||
__EXTERN void shell_exit();
|
||||
|
||||
extern void shell_putc(char c);
|
||||
extern void shell_puts(const char* str);
|
||||
extern void shell_printf(const char* format, ...);
|
||||
__EXTERN char shell_getc();
|
||||
__EXTERN void shell_gets(char* str, int n);
|
||||
|
||||
extern void shell_cls();
|
||||
__EXTERN void shell_putc(char c);
|
||||
__EXTERN void shell_puts(const char* str);
|
||||
__EXTERN void shell_printf(const char* format, ...);
|
||||
|
||||
__EXTERN void shell_write_string(const char* s, size_t len);
|
||||
|
||||
__EXTERN void shell_cls();
|
||||
#endif
|
||||
|
||||
@@ -30,7 +30,8 @@ BIN = \
|
||||
futex.kex \
|
||||
atexit_test.kex \
|
||||
abort_test.kex \
|
||||
strftime_test.kex
|
||||
strftime_test.kex \
|
||||
multithread_io.kex
|
||||
|
||||
all: $(BIN)
|
||||
|
||||
|
||||
@@ -26,5 +26,6 @@ cp clayer/logo.png /tmp0/1/tcc_samples/logo.png
|
||||
../tcc atexit_test.c -o /tmp0/1/tcc_samples/atexit_test
|
||||
../tcc abort_test.c -o /tmp0/1/tcc_samples/abort_test
|
||||
../tcc strftime_test.c -o /tmp0/1/tcc_samples/strftime_test
|
||||
../tcc multithread_io.c -o /tmp0/1/tcc_samples/multithread_io
|
||||
"/sys/File managers/Eolite" /tmp0/1/tcc_samples
|
||||
exit
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ksys.h>
|
||||
|
||||
#define NUM_THREADS 16
|
||||
#define ITERATIONS 16
|
||||
#define STACK_SIZE 64 * 1024
|
||||
|
||||
int multithread_done = 0;
|
||||
|
||||
#define MUTLITHREAD_EXIT \
|
||||
__asm__ volatile( \
|
||||
"lock incl %0" \
|
||||
: "+m"(multithread_done) \
|
||||
: \
|
||||
: "cc"); \
|
||||
_ksys_exit();
|
||||
|
||||
// Функция, которую выполняет каждый поток
|
||||
void thread_writer()
|
||||
{
|
||||
ksys_thread_t t;
|
||||
_ksys_thread_info(&t, -1);
|
||||
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
|
||||
printf("[thread %ld] %d: ", t.pid, i + 1);
|
||||
puts("idk something...\n");
|
||||
_ksys_thread_yield();
|
||||
}
|
||||
|
||||
MUTLITHREAD_EXIT;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("=== Start console multithread test ===\n");
|
||||
|
||||
// Создание потоков
|
||||
for (long i = 0; i < NUM_THREADS; i++) {
|
||||
void* stack = malloc(STACK_SIZE);
|
||||
if (_ksys_create_thread(thread_writer, stack + STACK_SIZE) == -1) {
|
||||
perror("can't crate thread\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
while (multithread_done < NUM_THREADS) {
|
||||
_ksys_thread_yield();
|
||||
}
|
||||
|
||||
printf("=== Done ===\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -36,12 +36,20 @@ GAS_SRC = {
|
||||
"string/memmove.s"
|
||||
}
|
||||
|
||||
OBJS = { "libc.c" }
|
||||
OBJS = {
|
||||
"libc.c"
|
||||
}
|
||||
|
||||
tup.append_table(OBJS, tup.foreach_rule(GAS_SRC, "as --32 %f -o %o", "%B.o"))
|
||||
|
||||
tup.rule(OBJS, "kos32-tcc" .. CFLAGS .. INCLUDES .. " %f -o %o " .. " && strip %o --strip-unneeded ", "libc.o")
|
||||
tup.rule("libc.o", "objconv -fcoff32 %f %o " .. tup.getconfig("KPACK_CMD"), "%B.obj")
|
||||
tup.rule(OBJS, "kos32-tcc" .. CFLAGS .. INCLUDES .. " %f -o %o ", "libc.o_elf")
|
||||
tup.rule("libc.o_elf", "objconv -fcoff32 %f %o", "libc.o")
|
||||
|
||||
tup.rule(
|
||||
{ "libc.o", extra_inputs = { "libc.lds" } },
|
||||
"kos32-ld -r -Tlibc.lds %f -o %o" .. tup.getconfig("KPACK_CMD"),
|
||||
"%B.obj"
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "sys/seekdir.c"
|
||||
#include "sys/socket.c"
|
||||
#include "sys/telldir.c"
|
||||
#include "sys/conio.c"
|
||||
|
||||
#include "stdio/clearerr.c"
|
||||
#include "stdio/conio.c"
|
||||
@@ -128,7 +129,51 @@
|
||||
#include "misc/basename.c"
|
||||
#include "misc/dirname.c"
|
||||
|
||||
#include "../../lib/libshell/shell_cls.c"
|
||||
#include "../../lib/libshell/shell_exit.c"
|
||||
#include "../../lib/libshell/shell_get_pid.c"
|
||||
#include "../../lib/libshell/shell_getc.c"
|
||||
#include "../../lib/libshell/shell_gets.c"
|
||||
#include "../../lib/libshell/shell_init.c"
|
||||
#include "../../lib/libshell/shell_ping.c"
|
||||
#include "../../lib/libshell/shell_printf.c"
|
||||
#include "../../lib/libshell/shell_putc.c"
|
||||
#include "../../lib/libshell/shell_puts.c"
|
||||
#include "../../lib/libshell/shell_write_string.c"
|
||||
|
||||
|
||||
#include "sys/mutex.h"
|
||||
|
||||
void __libc_init_all_mutexes(void)
|
||||
{
|
||||
size_t count = __stop_mutex_init_array - __start_mutex_init_array;
|
||||
|
||||
if(count == 0)
|
||||
{
|
||||
_ksys_debug_puts("no mutexs to init");
|
||||
_ksys_exit();
|
||||
}
|
||||
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
_ksys_debug_puts("init mutex\n");
|
||||
__libc_mutex_t* mutex = (__libc_mutex_t*)__start_mutex_init_array[i];
|
||||
|
||||
__libc_mutex_init(mutex);
|
||||
}
|
||||
}
|
||||
|
||||
int lib_init()
|
||||
{
|
||||
__libc_init_all_mutexes();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ksys_dll_t EXPORTS[] = {
|
||||
|
||||
{ "lib_init", &lib_init },
|
||||
|
||||
{ "clearerr", &clearerr },
|
||||
{ "debug_printf", &debug_printf },
|
||||
{ "fclose", &fclose },
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
OUTPUT_FORMAT("pe-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text : {
|
||||
*(.text)
|
||||
. = ALIGN(4);
|
||||
}
|
||||
|
||||
.rodata : {
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
|
||||
. = ALIGN(4);
|
||||
|
||||
__start_mutex_init_array = .;
|
||||
KEEP(*(.mutex_init_array))
|
||||
__stop_mutex_init_array = .;
|
||||
|
||||
. = ALIGN(4);
|
||||
}
|
||||
|
||||
.data : {
|
||||
*(.data)
|
||||
. = ALIGN(4);
|
||||
}
|
||||
|
||||
.bss : {
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
}
|
||||
}
|
||||
@@ -72,4 +72,3 @@ int con_init(void)
|
||||
{
|
||||
return con_init_opt(-1, -1, -1, -1, __con_caption);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "conio.h"
|
||||
#include "../sys/_conio.h"
|
||||
#include "sys/ksys.h"
|
||||
|
||||
size_t fread(void *restrict ptr, size_t size, size_t nmemb, FILE *restrict stream) {
|
||||
@@ -19,8 +19,7 @@ size_t fread(void *restrict ptr, size_t size, size_t nmemb, FILE *restrict strea
|
||||
}
|
||||
|
||||
if(stream==stdin){
|
||||
con_init();
|
||||
con_gets((char*)ptr, bytes_count+1);
|
||||
console_gets((char*)ptr, bytes_count+1);
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,45 +1,46 @@
|
||||
#include <stdio.h>
|
||||
#include "conio.h"
|
||||
#include "../sys/_conio.h"
|
||||
#include <sys/ksys.h>
|
||||
#include <errno.h>
|
||||
#include <shell_api.h>
|
||||
|
||||
size_t fwrite(const void *restrict ptr, size_t size, size_t nmemb, FILE *restrict stream) {
|
||||
unsigned bytes_written = 0;
|
||||
unsigned bytes_count = size * nmemb;
|
||||
|
||||
if(!stream){
|
||||
errno = EBADF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(size<=0 || nmemb<=0){
|
||||
errno = EINVAL;
|
||||
stream->error=errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(stream==stdout){
|
||||
con_init();
|
||||
con_write_string((char*)ptr, bytes_count);
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
if(stream==stderr){
|
||||
for (size_t i = 0; i < bytes_count; i++) {
|
||||
char c = *(char*)(ptr+i);
|
||||
_ksys_debug_putc(c);
|
||||
}
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
if(stream->mode != _FILEMODE_R){
|
||||
unsigned status = _ksys_file_write_file(stream->name, stream->position, bytes_count, ptr, &bytes_written);
|
||||
if (status != KSYS_FS_ERR_SUCCESS) {
|
||||
errno = EIO;
|
||||
stream->error = errno;
|
||||
return 0;
|
||||
}
|
||||
stream->position+=bytes_written;
|
||||
}
|
||||
return bytes_written/size;
|
||||
size_t fwrite(const void* restrict ptr, size_t size, size_t nmemb, FILE* restrict stream)
|
||||
{
|
||||
unsigned bytes_written = 0;
|
||||
unsigned bytes_count = size * nmemb;
|
||||
|
||||
if (!stream) {
|
||||
errno = EBADF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (size <= 0 || nmemb <= 0) {
|
||||
errno = EINVAL;
|
||||
stream->error = errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stream == stdout) {
|
||||
console_write((char*)ptr, bytes_count);
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
if (stream == stderr) {
|
||||
for (size_t i = 0; i < bytes_count; i++) {
|
||||
char c = *(char*)(ptr + i);
|
||||
_ksys_debug_putc(c);
|
||||
}
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
if (stream->mode != _FILEMODE_R) {
|
||||
unsigned status = _ksys_file_write_file(stream->name, stream->position, bytes_count, ptr, &bytes_written);
|
||||
if (status != KSYS_FS_ERR_SUCCESS) {
|
||||
errno = EIO;
|
||||
stream->error = errno;
|
||||
return 0;
|
||||
}
|
||||
stream->position += bytes_written;
|
||||
}
|
||||
return bytes_written / size;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include <stdio.h>
|
||||
#include <conio.h>
|
||||
#include "../sys/_conio.h"
|
||||
|
||||
int getchar(void) {
|
||||
con_init();
|
||||
|
||||
char c = 0;
|
||||
con_gets(&c, 2);
|
||||
console_gets(&c, 2);
|
||||
if (c == 0) {
|
||||
c = EOF;
|
||||
}
|
||||
|
||||
@@ -4,17 +4,16 @@
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
char *gets(char* str)
|
||||
char* gets(char* str)
|
||||
{
|
||||
con_init();
|
||||
if(con_gets(str, STDIO_MAX_MEM)==NULL){
|
||||
if (console_gets(str, STDIO_MAX_MEM) == NULL) {
|
||||
errno = EIO;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int str_len = strlen(str);
|
||||
if(str[str_len-1]=='\n'){
|
||||
str[str_len-1]='\0';
|
||||
if (str[str_len - 1] == '\n') {
|
||||
str[str_len - 1] = '\0';
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//#include "format_print.h"
|
||||
// #include "format_print.h"
|
||||
|
||||
int printf(const char *format, ...)
|
||||
int printf(const char* format, ...)
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
return vprintf(format, arg);
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
int ret = vprintf(format, arg);
|
||||
va_end(arg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "conio.h"
|
||||
#include "sys/ksys.h"
|
||||
#include "../sys/_conio.h"
|
||||
#include <sys/ksys.h>
|
||||
|
||||
int puts(const char *str)
|
||||
{
|
||||
con_init();
|
||||
con_write_asciiz(str);
|
||||
con_write_asciiz("\n");
|
||||
return strlen(str);
|
||||
}
|
||||
size_t len = strlen(str);
|
||||
console_write(str, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
/* Copyright (C) 2021 Logaev Maxim (turbocat2001), GPLv2 */
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
|
||||
int vsprintf(char* s, const char* format, va_list arg)
|
||||
{
|
||||
return vsnprintf(s, STDIO_MAX_MEM, format, arg);
|
||||
}
|
||||
|
||||
int vprintf(const char* format, va_list arg)
|
||||
{
|
||||
return vfprintf(stdout, format, arg);
|
||||
}
|
||||
/* Copyright (C) 2021 Logaev Maxim (turbocat2001), GPLv2 */
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
|
||||
int vsprintf(char* s, const char* format, va_list arg)
|
||||
{
|
||||
return vsnprintf(s, STDIO_MAX_MEM, format, arg);
|
||||
}
|
||||
|
||||
int vprintf(const char* format, va_list arg)
|
||||
{
|
||||
return vfprintf(stdout, format, arg);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
#include <conio.h>
|
||||
#include <sys/ksys.h>
|
||||
#include "../sys/_conio.h"
|
||||
|
||||
void _exit(int status)
|
||||
{
|
||||
if (__con_is_load) {
|
||||
con_exit(0);
|
||||
}
|
||||
console_exit();
|
||||
|
||||
_ksys_exit();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef __LIBC_SYS_CONIO_H_
|
||||
#define __LIBC_SYS_CONIO_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
char* console_gets(char* buff, size_t len);
|
||||
|
||||
void console_write(const char* ptr, size_t len);
|
||||
|
||||
void console_exit();
|
||||
|
||||
#endif // __LIBC_SYS_CONIO_H
|
||||
@@ -0,0 +1,59 @@
|
||||
#include <stdio.h>
|
||||
#include <shell_api.h>
|
||||
#include <conio.h>
|
||||
#include "_conio.h"
|
||||
#include "mutex.h"
|
||||
|
||||
AUTO_INIT_MUTEX(__conio_mutex);
|
||||
|
||||
|
||||
char* console_gets(char* buff, size_t len)
|
||||
{
|
||||
__libc_mutex_lock(&__conio_mutex);
|
||||
|
||||
char* ret = buff;
|
||||
|
||||
if (__shell_is_init < __SHELL_INIT_FAILED) {
|
||||
shell_gets(buff, len);
|
||||
}
|
||||
if (__shell_is_init == __SHELL_INIT_FAILED) {
|
||||
con_init();
|
||||
ret = con_gets(buff, len);
|
||||
}
|
||||
|
||||
__libc_mutex_unlock(&__conio_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void console_write(const char* ptr, size_t len)
|
||||
{
|
||||
__libc_mutex_lock(&__conio_mutex);
|
||||
|
||||
if (__shell_is_init < __SHELL_INIT_FAILED) {
|
||||
shell_write_string(ptr, len);
|
||||
}
|
||||
if (__shell_is_init == __SHELL_INIT_FAILED) {
|
||||
con_init();
|
||||
con_write_string((char*)ptr, len);
|
||||
}
|
||||
|
||||
__libc_mutex_unlock(&__conio_mutex);
|
||||
}
|
||||
|
||||
void console_exit()
|
||||
{
|
||||
__libc_mutex_lock(&__conio_mutex);
|
||||
|
||||
if (__shell_is_init < __SHELL_INIT_FAILED) {
|
||||
shell_exit();
|
||||
}
|
||||
if (__shell_is_init == __SHELL_INIT_FAILED) {
|
||||
|
||||
if (__con_is_load) {
|
||||
con_exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
__libc_mutex_unlock(&__conio_mutex);
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
#ifndef __LIBC_MUTEX_H
|
||||
#define __LIBC_MUTEX_H
|
||||
|
||||
#include <sys/ksys.h>
|
||||
|
||||
#define MUTEX_FREE 1
|
||||
#define MUTEX_LOCKED 0
|
||||
|
||||
typedef struct {
|
||||
volatile int lock_state;
|
||||
int id;
|
||||
} __libc_mutex_t;
|
||||
|
||||
#define AUTO_INIT_MUTEX(name) \
|
||||
__libc_mutex_t name; \
|
||||
static const __libc_mutex_t* const ptr_##name \
|
||||
__attribute__((section(".mutex_init_array"), used)) \
|
||||
= &name
|
||||
|
||||
extern const __libc_mutex_t* const __start_mutex_init_array[];
|
||||
extern const __libc_mutex_t* const __stop_mutex_init_array[];
|
||||
|
||||
inline int atomic_cas(volatile int* ptr, int old_val, int new_val)
|
||||
{
|
||||
int actual;
|
||||
asm_inline(
|
||||
"lock; cmpxchgl %2, %1" : "=a"(actual), "+m"(*ptr) : "r"(new_val), "0"(old_val) : "memory");
|
||||
return actual;
|
||||
}
|
||||
|
||||
inline static int __libc_mutex_init(__libc_mutex_t* m)
|
||||
{
|
||||
|
||||
m->lock_state = MUTEX_FREE;
|
||||
m->id = _ksys_futex_create((int*)&m->lock_state);
|
||||
return m->id > 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
inline static void __libc_mutex_lock(__libc_mutex_t* m)
|
||||
{
|
||||
|
||||
while (1) {
|
||||
uint32_t prev = atomic_cas(&m->lock_state, MUTEX_FREE, MUTEX_LOCKED);
|
||||
|
||||
if (prev == MUTEX_FREE) {
|
||||
return;
|
||||
}
|
||||
|
||||
_ksys_futex_wait(m->id, MUTEX_LOCKED, 0);
|
||||
}
|
||||
}
|
||||
|
||||
inline static int __libc_mutex_destroy(__libc_mutex_t* m)
|
||||
{
|
||||
return _ksys_futex_destroy(m->id);
|
||||
}
|
||||
|
||||
inline static void __libc_mutex_unlock(__libc_mutex_t* m)
|
||||
{
|
||||
|
||||
atomic_cas(&m->lock_state, MUTEX_LOCKED, MUTEX_FREE);
|
||||
|
||||
_ksys_futex_wake(m->id, 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user