tcp_input: on RST+ACK in SYN_SENT, unlock the socket mutex before
tcp_drop and leave through .drop_no_socket. tcp_drop frees the socket
and locks that mutex itself, so the network thread hung on it.
Assisted-by: Claude:claude-opus-5
Reviewed-on: KolibriOS/kolibrios#622
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: Kiril Lipatov <lipatov.kiril@gmail.com>
- the TX reclaim loop in int_handler multiplied sizeof.txfd by itself (mul eax) instead of by last_tx, so it looked 1024 bytes past tx_ring and never freed a descriptor
- it also left txfd.status set, and transmit treats a non-zero status as busy, so once the 16-entry ring wrapped every send ended in "TX overrun": DHCP fell back to link-local, ping showed "Socket error", while the link still read as connected
- reclaim only descriptors the device completed (TXFD_STATUS_C) and zero their status; transmit now checks for an unreclaimed buffer (virt_addr)
Seen on an EtherExpress Pro/100 in a Pentium II. Reproduced in QEMU (-cpu pentium2, i82557b): ping stopped at the 12th reply every time; with the fix it runs indefinitely, also under a UDP flood.
Reviewed-on: KolibriOS/kolibrios#725
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
Summary: an optical drive on an AHCI port was detected and then ignored,
so CD/DVD only worked with the controller switched to IDE mode. It now
shows up as /srN and ISO9660 discs are readable, including disc changes.
Details:
- ahci_atapi_cmd sends a SCSI command through the ATA PACKET command
(A bit in the command header, CDB in acmd, DMA when IDENTIFY PACKET
word 49 allows it, DMADIR when word 62 requires it). Built on top of it:
TEST UNIT READY, REQUEST SENSE, READ CAPACITY(10), READ(10), READ TOC
(start of the last session for multisession discs) and START STOP UNIT
for DISKFUNC.LoadTray.
- Drives are registered as sr0, sr1, ... with DISK_NO_INSERT_NOTIFICATION,
2048-byte sectors and read-only media; iso9660 mounts them as /srN/1.
They cannot be named cd*: fs_lfn.inc sends every path starting with "cd"
to the old ATAPI-over-IDE code.
- Disc change: the kernel lets go of a mounted medium only when querymedia
fails, so after a UNIT ATTENTION querymedia fails once and the kernel
immediately mounts the new disc. A READ(10) that hits UNIT ATTENTION
fails instead of silently reading the new disc.
- One ATAPI transfer is capped at (PRDT_MAX_ENTRIES - 1) * 4096 bytes, so
the PRDT always covers the whole request. The PRDT builder moved out of
ahci_rw_sectors into ahci_build_prdt and is shared by both paths.
- A command the drive refuses (an empty tray does that on every TEST UNIT
READY) restarts the port quietly instead of running the full recovery.
- Optical ports never busy-poll a long command and never switch the whole
controller to polling: missing interrupts are counted per port and only
that port's PxIE is turned off.
- Diagnostic output (command statistics, interrupt wakeups, register dumps
during init) is now behind AHCI_DBGLVL, off by default. Errors and one
line per detected device are still printed.
Tested: QEMU, VirtualBox and VMware (detection, listings and reads checked
against host checksums; eject/insert in QEMU and VirtualBox, a direct disc
swap in VirtualBox, an empty drive in VMware), SATA disk read/write on the
same controller in QEMU, and a GA-D525TUD (NM10) with an ASUS DRW-24B3ST:
detection, reading, disc change. The debug level change was build-tested
only.
Assisted-by: Claude Opus 5
Reviewed-on: KolibriOS/kolibrios#694
Reviewed-by: Burer <burer@kolibrios.org>
Reviewed-by: Ivan B <1+dunkaist@noreply.localhost>
Co-authored-by: leency <lipatov.kiril@gmail.com>
`tcp_output`: the window-update check computed `min(free, max_win - advertised)` instead of BSD's `min(free, max_win) - advertised`. With unread data in the receive buffer, every `send()` produced an empty ACK and never reached the persist state: no zero-window probes, and the connection hung.
- Clamp to the free space first, then subtract the advertised window.
- Compare signed: the result is negative when the window shrank.
Tested in QEMU with pcap: ~11000 empty ACKs in 0.6 s and no probe before the fix; 12 ACKs and a 1-byte persist probe after it.
Reviewed-on: KolibriOS/kolibrios#711
Reviewed-by: Burer <burer@kolibrios.org>
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Co-authored-by: leency <lipatov.kiril@gmail.com>
- `net_remove_device`: clear the slot's IPv4 settings, ARP table and counters, and drop its frames from the ethernet input queue.
- `ipv4_route`:
- skip slots without a device;
- an interface without an address routes broadcasts only;
- off-link without a gateway fails instead of resolving 0.0.0.0.
- `ipv4_output_raw`: check the route before resolving it.
- `eth_output`, `arp_output_request`: refuse a null device.
- `eth_output`: count a too-large frame on the device, not on `eax`.
Reviewed-on: KolibriOS/kolibrios#719
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
open_connection in http.obj left the socket open whenever connect()
failed. The kernel never reclaims sockets of a finished process
(socket_process_end is a stub), so every failed connect leaked a socket
with its two SOCKET_BUFFER_SIZE rings for good, and a late SYN+ACK could
still connect the orphan. WebView with a few dead image hosts ran the
kernel heap dry ("SOCKET_ring_create: Out of memory!"), after which every
application lost the network. Close the socket on the way out.
The socket() error check compared against 0, but the syscall returns -1
on failure; compare with -1.
The close() above exposed a second bug: tcp_connect took SOCKET.mutex
before creating the rings and returned from .nomem and .enoroute without
releasing it. Any later socket_free on that socket - close() from the
application, once http.obj does it - then waited for the mutex forever
and the thread became unkillable. Unlock on both error exits.
Assisted-by: Claude Fable 5.1 <noreply@anthropic.com>
A grayscale JPEG is decoded as Image.bpp8i with a 256-level gray
palette built from xor eax, eax, so every entry had alpha 0. After
img.convert to Image.bpp32 the picture was fully transparent: programs
that blend by alpha (WebView) reserved its room and drew nothing.
The palette now starts at 0xFF000000, as the PNG decoder fills its own.
Assisted-by: Claude Opus 5 <noreply@anthropic.com>
- Move ImgF to ISO (closed source)
- Move Examples to ISO (any normal app is a better example... and also there is already /sys/example.asm)
- Remove /sys/settings/kolibri.lbl as unnecessary
- Kpack /sys/settings/keymap.key (this is a binnary file so no matter, -2.5KB) and load it by 68.27
Reviewed-on: KolibriOS/kolibrios#721
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
Summary: disk_scan_partitions takes its three-sector buffer from
kernel_alloc but gave it back with the malloc heap's free, which reads a
chunk header that a kernel_alloc block does not have. Mounting a disk
with non-512-byte sectors could fault or corrupt the malloc heap.
Details:
The global mbr_buffer is used only for 512-byte sectors and only while no
other scan holds it; every other case allocates the buffer with
kernel_alloc. The release path still called free, the malloc heap
function: it looks at [ptr-8] for the chunk head. A kernel_alloc block is
page-aligned, so that is the tail of the previous page - a page fault when
that page is not mapped, otherwise a bogus header and possibly a damaged
heap.
Since "disk cache: support for sector sizes other than 512 bytes"
(9d022746f) every CD/DVD mount takes this path, so it is no longer a rare
race of two scans. It was hit as a page fault in free+0xF called from
disk_scan_partitions while an AHCI optical drive remounted a changed disc
in QEMU.
kernel_free keeps ebx and esi; the only caller, disk_media_changed, saves
ebx, esi and edi itself, so replacing the call does not disturb it.
Tested: kernel builds; in QEMU a CD on an AHCI port was mounted at boot and
remounted after swapping discs A -> B -> A, without faults, with this change
on top of origin/main and the AHCI ATAPI support branch.
Assisted-by: Claude Opus 5 <noreply@anthropic.com>
Reviewed-on: KolibriOS/kolibrios#695
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
Fixes KolibriOS/kolibrios#636
**Причина.** Каждое меню работает в своём потоке и рисует себя из холста `m.canvas`. Этот холст освобождал (`G.destroy`) не только сам поток меню, но и другие потоки:
- `Menu.close()` вызывается из главного потока и при переключении подменю. Он освобождал холст до `K.ExitID()`.
- При срабатывании шортката из подменю холст родительского меню освобождал поток-потомок.
При быстрых кликах поток меню в этот момент как раз внутри `DrawCanvas` (sysfn 65). Ядро читает из уже освобождённого буфера и получает page fault в режиме ядра, поэтому в логе CS=8. Кроме того, если поток сам выходил через `exit`/`escape` одновременно с чужим `close()`, получался двойной free.
**Исправление.** В [Menu.ob07](develop/cedit/SRC/Menu.ob07) убрал все четыре `G.destroy` для холста меню: в `exit`, `escape`, `close` и в ветке шорткатов. Холст и так создаётся лениво в `open()` при `m.canvas = NIL`. Меню создаются один раз при старте, и размер у них не меняется, так что холст теперь живёт всё время работы программы. Утечки нет, и кроме того больше нет выделения и освобождения памяти при каждом открытии меню.
Reviewed-on: KolibriOS/kolibrios#702
Reviewed-by: Burer <burer@kolibrios.org>
Reviewed-by: Alexey Ryabov <alex@b00bl1k.ru>
Co-authored-by: leency <lipatov.kiril@gmail.com>
Now I have sound on a pretty new UEFI machine (AMD 4500U) without IRQ attached. Also ran regression on 3 BIOS machines. All OK.
drivers/hdaudio: attach IRQ before enabling interrupts, poll when no IRQ line
- attach the interrupt handler before azx_init_chip enables GIE/CIE: an
unclaimed level IRQ made the kernel (irq_serv .try_other_irqs) call and
relink foreign handlers onto our line, corrupting the dispatch list
- no interrupt line (INTLINE=0xFF, UEFI without CSM): fall back to RIRB
polling plus a 10 ms TimerHS driving hda_irq; sound works on AMD Renoir
- acknowledge all STATESTS bits instead of codec №2 only
- serialize RIRB readers (timer/IRQ vs command thread) with aspinlock
- fix azx_int_disable (edx reused after azx_readl), quiesce before attach
- zero the unsolicited-event ring pointers, mask its write index
- move 'data fixups' after code and data so fasm converges
Reviewed-on: KolibriOS/kolibrios#679
Reviewed-by: Ivan B <1+dunkaist@noreply.localhost>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
The FAT/device error path in fat_Write jumped to the shared one-dword
epilogue with four dwords live, so ret returned into the error-code
slot and faulted in ring 0. Give the path its own named label.
Reviewed-on: KolibriOS/kolibrios#631
Reviewed-by: Burer <burer@kolibrios.org>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Summary: SOCKET_BUFFER_SIZE was 32 KiB, which caps a single TCP connection
at roughly 1 MB/s over a typical internet path regardless of the available
bandwidth.
Подробно:
The receive buffer size is the upper bound on the window a socket can
advertise, and a TCP connection cannot go faster than window / RTT. At the
old 4096*8 = 32 KiB, a path with a 32 ms round trip is limited to about
1 MB/s no matter how fast the link underneath is. Raising the buffer to
4096*32 = 128 KiB moves that ceiling to roughly 4 MB/s on the same path.
Nothing else needs adjusting: request_r_scale is derived from
SOCKET_BUFFER_SIZE in tcp_usreq, so the window scale we request grows with
the buffer automatically, and both tcp_output and tcp_respond clamp the
scaled value to the 16-bit header field. The constant keeps satisfying the
documented requirement of 4096*(power of two >= 8).
The cost is memory: each stream socket maps a send and a receive ring, so a
TCP socket now reserves 256 KiB of physical memory instead of 64 KiB (and
twice that in address space, since the rings are mirror-mapped). For a
browser holding a handful of connections open this is a few megabytes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
max_sectors_at_time only bounded a slice by the 16-bit transfer length
field of READ(10)/WRITE(10), i.e. 32 MB, so whatever the caller asked
for went to the device as a single command. The kernel disk cache hands
the driver up to CACHE_MAX_ALLOC_SIZE (4 MB) at once, so reading any
file larger than 4 MB produced one 4 MB bulk transfer.
USB sticks do not see such commands from other systems and some of them
wedge their firmware on it: the queue halts with XactErr and an
exhausted error counter, the device stops answering, drops off the bus
and re-enumerates in the middle of the operation. Observed on two
different sticks, reproducible on every file over 4 MB.
Cap a slice at 240 sectors (120 KB), the limit Linux usb-storage uses
for the same reason. The splitting loop was already there.
Assisted-by: Claude Opus 5 <noreply@anthropic.com>
Reviewed-on: KolibriOS/kolibrios#686
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
Sysfn 76 returns -1 for a missing device. The ARP conflict counter
check in .maintain_link treats any change of the value as a new
conflict, so when a device disappeared the counter jumped 0 -> -1 -> 0
across the reconnect and a bogus "IP address conflict" notification
popped up on every replug of a USB network device.
Skip the check when the query fails.
Assisted-by: Claude Opus 5 <noreply@anthropic.com>
Reviewed-on: KolibriOS/kolibrios#677
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
Sysfn 74 returns -1 for a missing device, not 0, so the device-presence
check in .maintain_link never took the .link_down path and the interface
stayed in connected state forever. As a result DHCP was never restarted
when a device reappeared on the same slot (e.g. an Android phone
re-enumerating in RNDIS tethering mode with a new random MAC), leaving
the interface with a stale IP and a dead gateway.
Compare against 1 (Ethernet), the same way the .link_up? path already
does, so a vanished device properly resets the interface state and DHCP
runs again on reconnect.
Assisted-by: Claude Opus 5 <noreply@anthropic.com>
Reviewed-on: KolibriOS/kolibrios#676
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
Serves PCI class 0C0330: LS/FS/HS devices on USB2 ports, SuperSpeed on
USB3 ports. The kernel stack knows only USB2 speeds, so SuperSpeed is
reported as high-speed and handled inside the driver. Falls back to
polling when the controller has no usable interrupt line.
Tested: flash drives, an external SSD, mice, keyboards.
Reviewed-on: KolibriOS/kolibrios#666
Reviewed-by: Ivan B <1+dunkaist@noreply.localhost>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
XDPascal для Колибри и Винды. С примерами.
Компиляторы убирают из бинарника недостижимые процедуры: два прохода,
на первом строится граф вызовов, на втором код мёртвых процедур не пишется.
Бинарники меньше в 1.5-5 раз. Ключ -nosmart отключает, вывод при этом
побайтово совпадает со старым компилятором.
Также снимаются кавычки с аргументов командной строки: без этого
make.bat не работал со сборкой не через Delphi.
xdpw_2020 - прежний компилятор, xdpw_2026 - новый.
Assisted-by: Claude Opus 5 <noreply@anthropic.com>
Reviewed-on: KolibriOS/kolibrios#646
Reviewed-by: Ivan B <1+dunkaist@noreply.localhost>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
I had an issue with 100% cpu load caused by this commit be847c5e1f
This PC is HP dc5800. Its audio card is PCI\VEN_8086&DEV_293E&REV_02 (ICH9 - 82801I) with build-in speaker.
So I Gemini wrote some code for me:
> This code implements a circular buffer to temporarily store unsolicited events, allowing the interrupt handler to quickly save data and immediately release the CPU. Now, instead of placing a direct load on the system, a background timer periodically "picks up" the accumulated events from this buffer and processes them safely.
Now it fixed on my PC. Also I've tested it on two machines and it also works well. Please take a look.
---------
Co-authored-by: Burer <burer@kolibrios.org>
Reviewed-on: KolibriOS/kolibrios#455
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Reviewed-by: Ivan B <1+dunkaist@noreply.localhost>
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Co-authored-by: leency <lipatov.kiril@gmail.com>
Load characters with lodsw only ever set ax. Anything left in the high half - including what this routine's own three-byte branch leaves there - would then push every following character into a longer form: an ASCII name off a Joliet CD came out as overlong three-byte sequences from the second character on. Narrow the input here, so every caller is safe.
Reviewed-on: KolibriOS/kolibrios#633
Reviewed-by: Burer <burer@kolibrios.org>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Co-authored-by: leency <lipatov.kiril@gmail.com>
Summary: the keepalive handler compared the wrong field against the TCB
state constants, and walked into freed memory when the socket it killed was
released by tcp_disconnect.
Details:
Two independent defects in the same branch of tcp_timer_640ms.
First, the state test read TCP_SOCKET.state. That field is the inherited
SOCKET.state, an SS_* bitmask, not the TCB state machine; comparing it
against TCPS_ESTABLISHED compared a bitmask against an enum and decided
nothing meaningful. The TCB state lives in t_state. The comparison is also
changed from `ja` to `jae`, so only embryonic connections -- those whose
handshake never completed within TCP_time_keep_init -- are torn down here.
A synchronized connection now always falls through to .dont_kill, where it
either gets a keepalive probe (SO_KEEPALIVE set) or simply rearms the timer,
as in BSD. Previously an idle but perfectly healthy connection could be
dropped without the application ever asking for keepalives.
Second, the kill path did
push eax
call tcp_disconnect
pop eax
jmp .loop
and .loop dereferences SOCKET.NextPtr of that socket. But tcp_disconnect
jumps straight to tcp_close for a not-yet-synchronized connection, and
tcp_close calls socket_free -- so NextPtr was read out of freed kernel heap
and the timer thread continued its walk down a dangling pointer. The
successor is now saved before the call and the loop resumes at .check_only,
which is exactly what the timed-wait branch at the end of the same loop
already does.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-on: KolibriOS/kolibrios#621
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Summary: socket_close() skipped both tcp_disconnect and socket_free for any
TCP socket that was not yet in the SS_ISCONNECTED state, leaking the socket
structure and leaving it on the net_sockets list forever.
Details:
The SS_ISCONNECTED gate in socket_close covered only fully established
connections. A socket closed while in SYN_SENT, SYN_RECEIVED or LISTEN, or
one that never connected at all, fell through to a bare `ret`: it was
neither disconnected nor freed. The 4 KiB socket structure and its two ring
buffers stayed allocated, the socket kept its place on net_sockets, its
timers kept being decremented by tcp_timer_640ms, and SOCKET.TID kept
pointing at a thread that was about to exit. A browser or any other
application that opens connections which fail to establish (refused,
filtered, or simply cancelled by the user) leaked one socket per attempt.
The gate is not needed: tcp_disconnect dispatches on the TCB state itself
and jumps straight to tcp_close -- which calls socket_free -- whenever
t_state is below TCPS_ESTABLISHED. Dropping the test therefore routes the
not-yet-synchronized cases to exactly the cleanup they were missing, and
leaves the established path untouched. The SS_ISDISCONNECTING test is kept,
so a second close() on a socket already shutting down is still a no-op.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-on: KolibriOS/kolibrios#620
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Summary: tcp_respond clamped the free receive space to 65535 and only then
applied RCV_SCALE, so scaled ACKs and keepalives advertised a window far
smaller than the one actually available.
Подробно:
The window field of a TCP header is 16 bits wide and, when window scaling is
in effect, carries the free space shifted right by RCV_SCALE. The two
operations therefore have to happen in that order: shift first, then clamp
the result to TCP_max_win.
tcp_respond did the opposite. With a receive buffer larger than 64 KiB and
RCV_SCALE = 2, free space of 128 KiB was first cut down to 65535 and then
shifted to 16383, announcing 64 KiB instead of the full 128 KiB. The larger
the buffer and the scale factor, the worse the under-advertisement -- the
window only ever shrank, so the effect was lost throughput rather than
corruption, but it silently defeated window scaling on exactly the responses
that carry the window most often.
tcp_output already gets this right (it compares against TCP_max_win shl
RCV_SCALE before writing the field); tcp_respond now agrees with it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tcp_set_persist takes the socket pointer in eax and uses ebx as a
scratch register to compute the RTO:
mov ebx, [eax + TCP_SOCKET.t_srtt]
shr ebx, 2
add ebx, [eax + TCP_SOCKET.t_rttvar]
shr ebx, 1
mov cl, [eax + TCP_SOCKET.t_rxtshift]
shl ebx, cl
By the time the persist timer is armed ebx therefore holds the timeout
value, not the socket. The flag store nevertheless went through ebx, so
it wrote to the linear address <RTO> + TCP_SOCKET.timer_flags -- an
unmapped low address -- instead of setting timer_flag_persist on the
socket.
Any TCP connection whose peer advertises a zero window takes this path
from tcp_output.enter_persist and faults the kernel:
K : Page fault
K : EBX : 0000000A
K : EIP : 80037DF3 (tcp_set_persist, the flag store)
K : Process - forced terminate PID: 00000005
Observed with NetSurf on a HTTP/2 connection to www.redhat.com, where
twelve multiplexed streams closed the receive window. Store the flag
through eax, which tcpt_rangeset leaves untouched.
Assisted-by: Claude Opus 5 <noreply@anthropic.com>
Summary: the received window scale option was stored into SND_SCALE, which
the connection setup code then immediately overwrote with zero, so every
peer window was interpreted unscaled.
Details:
RFC 1323 negotiation is completed in two places -- the SYN_RECEIVED branch
and the active-open branch of tcp_input. Both do
mov ax, word[ebx + TCP_SOCKET.requested_s_scale]
mov word[ebx + TCP_SOCKET.SND_SCALE], ax
relying on the declared order of the four adjacent bytes SND_SCALE,
RCV_SCALE, requested_s_scale, request_r_scale to move both factors at once.
requested_s_scale, however, was never filled in: the option parser wrote the
peer's shift count into SND_SCALE directly, and that value was then clobbered
by the word move with the zero left in requested_s_scale by socket_alloc.
The result was that SND_SCALE ended up 0 on every connection while
TF_RCVD_SCALE was set, so a peer advertising, say, 64 KiB with a shift of 7
was read as advertising 512 bytes. Sending to any modern host was throttled
to a fraction of the real window.
The parser now stores into requested_s_scale, where the setup code expects
it, and clamps the value to TCP_max_winshift (14) as required by RFC 1323 --
a peer sending a larger shift must not be allowed to make our SND_WND
computation shift out of range.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-on: KolibriOS/kolibrios#619
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Co-authored-by: leency <lipatov.kiril@gmail.com>
- Add `bbench` to IMG and System Panel
- Universal benchmark with 17 tests for CPU, graphics, memory and disk
- Tests can be toggled and configured
- Generates derailed reports in HTML
- Remove `MGB` and `FSPEED` from System Panel, move them from IMG to ISO
---------
Co-authored-by: Burer <burer@kolibrios.org>
Reviewed-on: KolibriOS/kolibrios#561
Reviewed-by: bad_Dr3dd0x <1702+bad_dr3dd0x@noreply.localhost>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
For chunked responses HTTP_receive added the whole buffer tail to
content_received every time it consumed a chunkline. When several
chunks arrived in one TCP segment, the same bytes were counted once
per chunkline (observed: content_received = 42 MB for an 83 KB page);
the value only became exact at got_all_data. A client trusting the
counter mid-transfer read far past the buffer and page-faulted.
In plain buffered mode recompute the exact value from the pointers
instead: min(chunk_ptr, write_ptr) - content_ptr, the same formula
.got_all_data_chunked uses. Data below chunk_ptr is decoded and
contiguous; bytes in [chunk_ptr, write_ptr) are still raw (unconsumed
chunkline + partial chunk). Stream/ring modes keep the running add:
there data is consumed as it arrives, so the incremental count is
correct.
---------
Co-authored-by: Burer <burer@kolibrios.org>
Reviewed-on: KolibriOS/kolibrios#569
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
I wrote an autotest for Netsurf. After 130 test run the system could not
create any new process anymore. Now this is fixed. Result:
916 OK, 0 CRASH, 0 HANG
Futexes (sysfn 77) live in the per-process handle table (PROC.htab)
and are allocated from the kernel's small-object heap via
create_object. The only code path that ever frees one is
destroy_object, which runs solely on an explicit FUTEX_DESTROY call --
and real programs never make it: newlib-based applications create a
dozen or so futexes at startup for their internal locks (malloc,
stdio) and simply exit, expecting the kernel to clean up. Nothing
does: destroy_process tears down HDLLs and page tables but never
walks the handle table.
Each leaked futex pins 48 bytes of the kernel malloc arena, and that
arena is a single fixed 128 KB block (init_malloc has no grow path).
After roughly two thousand leaked handles -- a few hundred to a few
thousand application launches within one uptime -- kernel malloc()
starts failing system-wide. The first visible casualty is
load_library: it can no longer allocate a DLLDESCR, so every dll.obj
load in every new process fails from that point on ("cannot load
library"), which is easy to mistake for a userland problem.
Reproduced by repeatedly launching a newlib application: the arena
filled with ~1750 48-byte chunks carrying the 'FUTX' magic (confirmed
by dumping the live arena; mst.topsize had dropped to 32 bytes with
free physical memory and kernel heap space still abundant), and dll
loading died after ~130 launches.
Fix: in destroy_process, after destroy_all_hdlls, walk the process's
handle table and free every live object. Free slots hold small
free-list indices and the reserved stdin/stdout/stderr handles hold
small values, so a bounds check against OS_BASE skips them; live
slots hold kernel pointers and are additionally verified by the
'FUTX' magic. If other object kinds are ever added to the handle
table, they will need their own destructors here -- the magic check
makes this walk skip them safely rather than crash.
---------
Co-authored-by: Burer <burer@kolibrios.org>
Reviewed-on: KolibriOS/kolibrios#567
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
Co-committed-by: leency <lipatov.kiril@gmail.com>
I wrote an autotest that runs Netsurf a lot of times. While running this
test I always faced the hang issue. First thought was about network
and sockets but QEMU debug through telnet revealed the issue in timers.
Now there is no hang after this fix.
timer_hs and cancel_timer_hs hold the global timer-list lock
(lock_timer_list/unlock_timer_list) across a short critical section
of plain list-pointer stores, without disabling interrupts. If the
owning thread is preempted inside that window, it can never be
scheduled again while a higher-priority thread is runnable: the
scheduler is strictly priority-based and osloop's check_timers (top
priority) busy-waits for the same lock via change_task, which never
descends to a lower-priority ring while its own ring has a runnable
thread. The result is a permanent, whole-system livelock -- not a
one-off race, but a deterministic outcome whenever the preemption
lands inside the section.
Reproduced by driving thousands of blocking TCP connects (each one
calls timer_hs for its connect timeout) through a browser under QEMU,
where interrupts tend to land on translation-block boundaries right
after the lock's cmpxchg. Confirmed via the QEMU monitor: osloop
spinning forever in lock_timer_list while the lock owner sat, fully
preempted, one instruction into timer_hs's critical section.
Fix: wrap the lock/insert-or-remove/unlock sequence in
timer_hs and cancel_timer_hs with pushfd/cli ... popfd, making it
atomic with respect to preemption. The wait loop inside
lock_timer_list is unaffected -- change_task manages IF on its own,
so spinning there with interrupts off cannot itself hang anything.
Reviewed-on: KolibriOS/kolibrios#564
Reviewed-by: Ivan B <1+dunkaist@noreply.localhost>
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Co-authored-by: Kiril Lipatov <lipatov.kiril@gmail.com>
Co-committed-by: Kiril Lipatov <lipatov.kiril@gmail.com>
The issue:
1. Put kolibri.img on Flash
2. Load Kolibri from Flash
3. On Blue screen set [e] Floppy image: 1. floppy
4. Press Enter to boot
**Old result:** error, system hang ("jmp $" is infinite cycle)
**New result:** error, you can change options (set [e] = "3. preloaded image" in current case) and continue boot
I often have this issue after testing Kolibri in QEMU and then coping image on Flash to run it on real hardware.
If I forgret to change [e] option ffrom 1 to 3 I had to reboot.
Reviewed-on: KolibriOS/kolibrios#530
Reviewed-by: Burer <burer@kolibrios.org>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Co-authored-by: leency <lipatov.kiril@gmail.com>
Co-committed-by: leency <lipatov.kiril@gmail.com>
- "Welcome" menu item now uses absolute path `/sys/welcome.htm` (relative path failed to open when other tab was already open).
- Add full RU and ES translations of welcome.htm, keeping the original tone, plus per-language build rules
- Fix typos/grammar, names and trailing whitespace in EN welcome.htm
- Add <head> tag with proper <meta charset="..."> to all three language versions
---------
Co-authored-by: Burer <burer@kolibrios.org>
Reviewed-on: KolibriOS/kolibrios#466
Reviewed-by: Burer <burer@kolibrios.org>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Reviewed-by: Andrew <15+ace-dent@noreply.localhost>
Co-authored-by: leency <lipatov.kiril@gmail.com>
Co-committed-by: leency <lipatov.kiril@gmail.com>
- proper fix of line break
- new refresh / stop icons
- more comfortable debug mode
- remove old comments from code
- fix very old issue with text overlapping
- line break on '-'
---------
Co-authored-by: Burer <burer@kolibrios.org>
Reviewed-on: KolibriOS/kolibrios#474
Co-authored-by: leency <lipatov.kiril@gmail.com>
Co-committed-by: leency <lipatov.kiril@gmail.com>
## app_plus: fix calling opendial and rework floppy-mode warning window
- Fix: bump MEMSIZE 40K => 60K so the Open file dialog starts.
- UI: drop the fake dir-listing mockup for a single icon + clearer text; remove unused SCRX/SCRY/kolibrios_dirs.
- UI: reposition header/description/buttons to the new CONX/CONY layout.
- Text: rewrite RU+EN warning - explain floppy mode and how to mount /kolibrios.
- Review: fix CONY comment + English grammar.
---------
Co-authored-by: Burer <burer@kolibrios.org>
Reviewed-on: KolibriOS/kolibrios#460
Co-authored-by: leency <lipatov.kiril@gmail.com>
Co-committed-by: leency <lipatov.kiril@gmail.com>
## WebView 3.97
- Fix: closing `</font>` pops `text_colors` by its own count, not `bg_colors` — no more dropping the default text color (`set_style.h`).
- Fix: `_cache::clear()` also resets `current_type` and `current_charset` (`cache.h`).
- Feature: `<li>` inside `<nav>` is rendered inline, separated by a single space (`set_style.h`).
- Cleanup: remove dead `src = …` assignments in View Source; `<font>` counting reads `src_orig` directly, behavior unchanged (`show_src.h`).
- Chore: bump version to `WebView 3.97` (`const.h`).
- Content: update test/home pages, add a hidden Easter-egg link to the test page (`res/test.htm`, `res/homepage_*.htm`).
---------
Co-authored-by: Burer <burer@kolibrios.org>
Reviewed-on: KolibriOS/kolibrios#459
Co-authored-by: leency <lipatov.kiril@gmail.com>
Co-committed-by: leency <lipatov.kiril@gmail.com>
- Bigger fonts
- System colors
- Code refactoring to make UI flexible and more readable
- Move from ISO to IMG
- Add to main menu, add to desktop instead of Calc, remove from App+
- Localization to all system languages
- Source code file is now UTF-8
Co-authored-by: Burer <burer@kolibrios.org>
Reviewed-on: KolibriOS/kolibrios#189
Reviewed-by: Max Logaev <maxlogaev@proton.me>
Co-authored-by: Kiril Lipatov <lipatov.kiril@gmail.com>
Co-committed-by: Kiril Lipatov <lipatov.kiril@gmail.com>
- LMB to open file, RMB to show in folder
- fix: correctly open folders
- fix UI: better list alignment
- Eolite: optimize OpenDir
- SelectList_ProcessMouse() better react on click
Reviewed-on: KolibriOS/kolibrios#191
Reviewed-by: Max Logaev <maxlogaev@proton.me>
Co-authored-by: leency <lipatov.kiril@gmail.com>
Co-committed-by: leency <lipatov.kiril@gmail.com>
- adopt window size to screen size
- bigger fonts
- proper colored 'S' and 'L' buttons
- fix issue: after won the game clicks count always increased to max
- code refactoring, translate comments to English
- help updated
Reviewed-on: KolibriOS/kolibrios#181
Reviewed-by: Max Logaev <maxlogaev@proton.me>
Co-authored-by: leency <lipatov.kiril@gmail.com>
Co-committed-by: leency <lipatov.kiril@gmail.com>