libc: квирки DSS — возврат WRITE и лимит манипуляторов; тесты fdmax/fbench
- ESTEX WRITE ($14) на успехе возвращает DE=0, а НЕ счётчик записанного (вопреки докам; solid-c в своём fflush тоже отключил сравнение по счётчику) — write() теперь судит по CF/A: CF=0&A=0 → n, CF=0&A!=0 → ENOSPC/-1 - DSS выдаёт 8 манипуляторов (fd 2..9; fd 1 держит шелл под запущенный exe), а 9-й OPEN не возвращает 06h — ВЕШАЕТ систему; предохранитель _fd_guard: счётчик в open()/close(), отказ EMFILE без захода в DSS - tests/fdmax — эмпирика лимита (8 хендлов, затем EMFILE=6); tests/fbench — бенчмарк буферизации (floor 512-байтными read, оценка небуферизованного по 1-байтным, fgetc/fgets/fputc) - filetest расширен: raw-probe возврата write, сценарий r+ (чтение-запись-чтение с инвалидацией буфера), ungetc, fprintf Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
# Build fbench.exe — бенчмарк буферизованного FILE* по BIG.TXT.
|
||||
# BIG.TXT (100 КБ) нужен тесту — кладём на дискету и при одиночном
|
||||
# `make run` (берём из tests/seek).
|
||||
|
||||
PROJ_ROOT := $(abspath $(CURDIR)/../..)
|
||||
EXAMPLE := fbench
|
||||
EXTRA_DATA := ../seek/big.txt
|
||||
include $(PROJ_ROOT)/app.mk
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* fbench — бенчмарк буферизации FILE* (вариант B+) с опорными замерами.
|
||||
*
|
||||
* 0a. read() блоками по 512 — «пол»: чистая скорость диск+syscall,
|
||||
* ровно те же вызовы, что делает буферный слой изнутри;
|
||||
* 0b. read() по 1 байту (16 КБ) — имитация НЕбуферизованного fgetc,
|
||||
* ×6.25 даёт оценку на весь файл;
|
||||
* 1. fgetc по всему файлу (102400 байт);
|
||||
* 2. fgets построчно;
|
||||
* 3. fputc 32 КБ (буфер: ~64 write-syscall'а вместо 32768).
|
||||
*
|
||||
* Интерпретация: если (1) ≈ (0a) — буферизация упирается в диск и
|
||||
* работает идеально; выигрыш против небуферизованного = (0b)×6.25 − (1).
|
||||
* Время — time(), секундная гранулярность. На дискете доминирует FDD;
|
||||
* для чистого замера скопировать fbench.exe + big.txt на HDD (C:).
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
static char blk[512];
|
||||
static char line[128];
|
||||
|
||||
int main(void)
|
||||
{
|
||||
long n;
|
||||
int c, fd, r;
|
||||
time_t t0, t1;
|
||||
|
||||
/* ----- 0a. Пол: блочный read по 512 ----- */
|
||||
fd = open("BIG.TXT", O_RDONLY);
|
||||
if (fd < 0) { puts("BIG.TXT not found"); return 1; }
|
||||
t0 = time(NULL);
|
||||
n = 0;
|
||||
while ((r = read(fd, blk, 512)) > 0) n += r;
|
||||
t1 = time(NULL);
|
||||
printf("read512: %ld bytes, %ld s (floor)\n", n, (long)(t1 - t0));
|
||||
close(fd);
|
||||
|
||||
/* ----- 0b. Имитация небуферизованного fgetc: read по 1 байту ----- */
|
||||
fd = open("BIG.TXT", O_RDONLY);
|
||||
t0 = time(NULL);
|
||||
for (n = 0; n < 16384L; n++) {
|
||||
if (read(fd, blk, 1) != 1) break;
|
||||
}
|
||||
t1 = time(NULL);
|
||||
printf("read1 : %ld bytes, %ld s (x6.25 = unbuffered est.)\n",
|
||||
n, (long)(t1 - t0));
|
||||
close(fd);
|
||||
|
||||
/* ----- 1. fgetc по всему файлу ----- */
|
||||
FILE *fp = fopen("BIG.TXT", "r");
|
||||
if (!fp) { puts("fopen failed"); return 1; }
|
||||
t0 = time(NULL);
|
||||
n = 0;
|
||||
while ((c = fgetc(fp)) != EOF) n++;
|
||||
t1 = time(NULL);
|
||||
printf("fgetc : %ld bytes, %ld s\n", n, (long)(t1 - t0));
|
||||
|
||||
/* ----- 2. fgets построчно ----- */
|
||||
rewind(fp);
|
||||
t0 = time(NULL);
|
||||
n = 0;
|
||||
while (fgets(line, sizeof(line), fp)) n++;
|
||||
t1 = time(NULL);
|
||||
printf("fgets : %ld lines, %ld s\n", n, (long)(t1 - t0));
|
||||
fclose(fp);
|
||||
|
||||
/* ----- 3. fputc 32 КБ ----- */
|
||||
fp = fopen("FBENCH.TMP", "w");
|
||||
if (!fp) { puts("cannot create FBENCH.TMP"); return 1; }
|
||||
t0 = time(NULL);
|
||||
for (n = 0; n < 32768L; n++) {
|
||||
if (fputc('x', fp) == EOF) { puts("fputc error"); return 1; }
|
||||
}
|
||||
if (fclose(fp)) { puts("fclose error"); return 1; }
|
||||
t1 = time(NULL);
|
||||
printf("fputc : 32768 bytes, %ld s\n", (long)(t1 - t0));
|
||||
unlink("FBENCH.TMP");
|
||||
|
||||
puts("fbench done.");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
# Build fdmax.exe — проверка лимита открытых файлов DSS/FILE-таблицы.
|
||||
# TEST.TXT нужен тесту как открываемый файл — кладём на дискету
|
||||
# и при одиночном `make run` (берём из tests/cat).
|
||||
|
||||
PROJ_ROOT := $(abspath $(CURDIR)/../..)
|
||||
EXAMPLE := fdmax
|
||||
EXTRA_DATA := ../cat/test.txt
|
||||
include $(PROJ_ROOT)/app.mk
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* fdmax — эмпирическая проверка лимита одновременно открытых файлов.
|
||||
*
|
||||
* ФАКТ (прогон 2026-07-06, DSS 1.71.57): DSS выдал 8 манипуляторов
|
||||
* (fd 2..9; fd 1 держит шелл DSS под запущенный .exe), а 9-й OPEN
|
||||
* НЕ вернул ошибку — ПОВЕСИЛ систему. После этого в libc/io/open.c
|
||||
* добавлен предохранитель _fd_guard (отказ EMFILE на 9-м open без
|
||||
* захода в DSS), и этот тест снова безопасен.
|
||||
*
|
||||
* 1) Низкий уровень: open("TEST.TXT") в цикле — ожидание: 8 хендлов,
|
||||
* затем EMFILE=6 от предохранителя libc (не от DSS!).
|
||||
* 2) Высокий уровень: fopen до NULL — таблица OPEN_MAX (8), EMFILE.
|
||||
*
|
||||
* Требует TEST.TXT на диске (без него обе фазы дадут ENOENT=3).
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#define TRY_MAX 32
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int fds[TRY_MAX];
|
||||
int n = 0;
|
||||
|
||||
/* ----- 1. Голые манипуляторы DSS ----- */
|
||||
errno = 0;
|
||||
while (n < TRY_MAX) {
|
||||
int fd = open("TEST.TXT", O_RDONLY);
|
||||
if (fd < 0) break;
|
||||
fds[n++] = fd;
|
||||
printf("open #%d -> fd=%d\n", n, fd);
|
||||
}
|
||||
printf("low-level: %d handles, then errno=%d (%s)\n",
|
||||
n, errno, strerror(errno));
|
||||
for (int i = 0; i < n; i++) close(fds[i]);
|
||||
|
||||
/* ----- 2. fopen / таблица FILE ----- */
|
||||
FILE *fps[TRY_MAX];
|
||||
int m = 0;
|
||||
errno = 0;
|
||||
while (m < TRY_MAX) {
|
||||
FILE *fp = fopen("TEST.TXT", "r");
|
||||
if (!fp) break;
|
||||
fps[m++] = fp;
|
||||
}
|
||||
printf("fopen: %d streams (OPEN_MAX=%d), then errno=%d (%s)\n",
|
||||
m, OPEN_MAX, errno, strerror(errno));
|
||||
for (int i = 0; i < m; i++) fclose(fps[i]);
|
||||
|
||||
puts("fdmax done.");
|
||||
return 0;
|
||||
}
|
||||
@@ -1,22 +1,41 @@
|
||||
/*
|
||||
* filetest — exercise minimal FILE * stream API (fopen/fclose/fputs/
|
||||
* fgets/fread/fwrite/fseek/ftell/feof + stdin/stdout/stderr).
|
||||
* filetest — exercise the buffered FILE * stream API (variant B+).
|
||||
*
|
||||
* Steps:
|
||||
* 1. fopen("FILE.TXT","w"), fputs+fputc lines, fclose.
|
||||
* 0. RAW probe: open/write/close — печатает ГОЛЫЙ возврат write()
|
||||
* (диагностика: что реально возвращает ESTEX WRITE в DE).
|
||||
* 1. fopen("FILE.TXT","w"), fputs+fputc lines, fclose (с errno).
|
||||
* 2. fopen("FILE.TXT","r"), fgets each line, fclose.
|
||||
* 3. fopen("r"), fread block, fseek, ftell, feof, fread again.
|
||||
* 4. fputs to stdout (sanity check console pseudo-stream).
|
||||
* 3. fopen("r"), fread block, fseek, ftell, feof.
|
||||
* 4. fputs to stdout/stderr (console pseudo-streams).
|
||||
* 5. "r+" mix: fgetc×10 → fputc×10 → fseek(0) → контроль, что
|
||||
* чтение видит записанное (инвалидация буфера); ungetc; fprintf.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const char *path = "FILE.TXT";
|
||||
|
||||
/* ----- 0. RAW write() return probe ----- */
|
||||
{
|
||||
int fd = open("WRT.TMP", O_WRONLY | O_CREAT | O_TRUNC);
|
||||
if (fd >= 0) {
|
||||
errno = 0;
|
||||
int w = write(fd, "12345", 5);
|
||||
printf(" raw write(5) -> %d, errno=%d\n", w, errno);
|
||||
close(fd);
|
||||
unlink("WRT.TMP");
|
||||
} else {
|
||||
printf(" raw probe: open failed errno=%d\n", errno);
|
||||
}
|
||||
}
|
||||
|
||||
/* ----- 1. Write via fputs + fputc ----- */
|
||||
{
|
||||
FILE *fp = fopen(path, "w");
|
||||
@@ -24,11 +43,14 @@ int main(void)
|
||||
printf("fopen(w) failed: errno=%d (%s)\n", errno, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
fputs("Hello from FILE*\n", fp);
|
||||
fputs("Second line via fputs\n", fp);
|
||||
int r1 = fputs("Hello from FILE*\n", fp);
|
||||
int r2 = fputs("Second line via fputs\n", fp);
|
||||
if (r1 || r2) printf(" fputs ret: %d %d\n", r1, r2);
|
||||
for (int i = '0'; i <= '9'; i++) fputc(i, fp);
|
||||
fputc('\n', fp);
|
||||
if (fclose(fp) != 0) puts("fclose: error");
|
||||
errno = 0;
|
||||
if (fclose(fp) != 0)
|
||||
printf("fclose: error, errno=%d (%s)\n", errno, strerror(errno));
|
||||
}
|
||||
|
||||
/* ----- 2. Read via fgets ----- */
|
||||
@@ -69,6 +91,32 @@ int main(void)
|
||||
fputs(" fputs to stderr works\n", stderr);
|
||||
fputc('!', stdout); fputc('\n', stdout);
|
||||
|
||||
/* ----- 5. "r+": чтение→запись→чтение + ungetc + fprintf ----- */
|
||||
{
|
||||
FILE *fp = fopen(path, "r+");
|
||||
if (!fp) { puts("fopen(r+) failed"); return 1; }
|
||||
for (int i = 0; i < 10; i++) fgetc(fp); /* поз. 10, readahead жив */
|
||||
for (int i = 0; i < 10; i++) fputc('X', fp); /* sync: запись на 10..19 */
|
||||
fseek(fp, 0L, SEEK_SET);
|
||||
char buf[24];
|
||||
size_t got = fread(buf, 1, 20, fp);
|
||||
int ok = (got == 20);
|
||||
for (int i = 10; i < 20; i++) if (buf[i] != 'X') ok = 0;
|
||||
printf(" r+ mix: %s (got=%u)\n", ok ? "OK" : "FAIL", (unsigned)got);
|
||||
|
||||
/* ungetc: прочитать байт, вернуть, прочитать снова */
|
||||
int c1 = fgetc(fp);
|
||||
ungetc(c1, fp);
|
||||
int c2 = fgetc(fp);
|
||||
printf(" ungetc: %s, ftell=%ld\n", c1 == c2 ? "OK" : "FAIL", ftell(fp));
|
||||
|
||||
/* fprintf в файл */
|
||||
fseek(fp, 0L, SEEK_END);
|
||||
int n = fprintf(fp, "num=%d hex=%04x\n", 42, 0xBEEF);
|
||||
printf(" fprintf -> %d chars\n", n);
|
||||
if (fclose(fp)) puts(" r+ fclose: error");
|
||||
}
|
||||
|
||||
puts("filetest done.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user