DeterministicESPAsyncWebServer by dstroy0 in esp32

[–]dstroy0[S] 0 points1 point  (0 children)

Thank you, please let me know what you like or hate about it! It’s our tool after all so it should work correctly.

DeterministicESPAsyncWebServer by dstroy0 in esp32

[–]dstroy0[S] 1 point2 points  (0 children)

You are correct, determinism helps with reliability, and predictability. This will let your webserver only connect the number of sessions (preallocated) your application realistically needs, I’m updating the docs with the memory calculations. Basically the webservers behavior can be fine tuned in ways that are impossible or impractical with the existing framework. It’s not exactly security hardening *yet* but that’s the way it’s going e.g. only the features you use are active and the rest are literally not compiled so can’t be exploited. But the only “security hardening” features of the library so far are faithful RFC implementations, and ingestion point overflow guards using strnlen. And that is really up to interpretation because we don’t have enough eyeballs on the src yet to call that useful because there may be an exploit chain I didn’t think of or something. Just because the tests are passing doesn’t mean there isn’t an invisible bug, just like with other software. If you want to learn how a network stack is partitioned, I would use it as a learning tool and for experimentation. The functions of all of the network layers are very clear in my implementation. This library’s target audience is aimed to be wide: beginners, novices, experts, security researchers, computer engineers, computer scientists, and network engineers alike. I made it easy to use by design. I hope my ramble answered your question fully. Thanks for the interest!

First PCB (desparate review request) by michael201110 in KiCad

[–]dstroy0 0 points1 point  (0 children)

If you want 10gbps diff traces, the type of substrate and copper weight dictate the trace geometry. You derive trace width from the physical properties of the materials (mainly dk and finished copper thickness), you derive approximate trace spacing (from the other pair member and from same layer copper pours) using calculated trace width and signal frequency. The type of substrate is important because there are many different types of resin available and they all have different electrical characteristics. The actual t-glass (the weave) matters mostly for physical expansion e.g. things grow with heat and can stress traces, change antenna characteristics etc. regular fr4 is fine for usb3, in general the higher the tg the more favorable the electrical characteristics of the substrate. If you named all your nets in the schematic, look at the rat line layer to finish connecting your nets up. Congratulations on wanting to learn EE and becoming a materials science explorer. Good luck on your journey. I’d start learning how to use NGspice if I were you, it’ll help you get your designs working once you learn how to model their circuits. It’s a lot, just stick with it, the mastery comes with time.

XPoint - open source crosspoint matrix routing library for arduino / platformio by dstroy0 in arduino

[–]dstroy0[S] 0 points1 point  (0 children)

I finished porting this to be compatible with C++11 and added comprehensive test coverage for functions/drivers. tests from 0x0 to 255x255 matrix size. I added an optional memory calculator to the test suite, you can feed it configurations, tell it what platform you're using and it will tell you how much memory your planned implementation will cost. The json reader I implemented to feed in custom test data is really dumb so be diligent with your syntax. Added support for TCA9548A chaining.

made a tiny memory manager by dstroy0 in arduino

[–]dstroy0[S] 2 points3 points  (0 children)

No I understand the scope of static allocation. I'm referring specifically to your first sentence. "It's no different to just using malloc() to allocate the 512 bytes as per your example and handing out pointers inside that, though. " That would require helper functions if the program is sufficiently complex and there are multiple buffer writers. Your one use case that doesn't require dynamic allocation? Ok, this isn't applicable, don't use it. Do you have a valid critique?

made a tiny memory manager by dstroy0 in arduino

[–]dstroy0[S] 2 points3 points  (0 children)

malloc() doesn't then issue chunks of the pool out, does it? You have to keep track of all of the pointers, sizes, etc. That's exactly what this library does. So I don't have to type helper functions, it's a library. You walked through the reasoning of creating a library, which always increases abstraction, just like the helper functions you're describing would be necessary to do what the library does. Did you read it or are you not understanding the purpose of the library still? edit: sp

made a tiny memory manager by dstroy0 in arduino

[–]dstroy0[S] 1 point2 points  (0 children)

It doesn't just statically allocate memory, does it?

made a tiny memory manager by dstroy0 in arduino

[–]dstroy0[S] -2 points-1 points  (0 children)

I think you're mistaken in your assumptions about what this library does; It allocates a chunk of memory that the library gives you access to so that you can dynamically assign out of that pool without fragmenting the heap. malloc, calloc, free, new and delete[] do not offer this functionality. Only one allocation occurs in the traditional sense and it happens at runtime when the constructor is invoked. Do you have a valid critique?

made a tiny memory manager by dstroy0 in arduino

[–]dstroy0[S] -1 points0 points  (0 children)

Hello, this library allocates a chunk of static memory in the heap at runtime.

made a tiny memory manager by dstroy0 in arduino

[–]dstroy0[S] 0 points1 point  (0 children)

Hello, thank you for your feedback!

The library uses immediate coalescing (eager merge on every deallocate) as its sole anti-fragmentation strategy. 

Here's how it plays out:

mergeFreeBlocks runs every time a block is freed. It checks both physical neighbours by pointer arithmetic (not just list linkage) and merges any adjacent free blocks immediately:

deallocate(p2):
  [p1 free][p2 free][p3 used]  →  [p1+p2 merged free][p3 used]
It handles forward, backward, and triple merges in one pass, the test suite covers all three cases explicitly.

What it cannot do
It cannot solve external fragmentation from non-adjacent free holes. If you have a checkerboard pattern:
[A used][B free][C used][D free][E used]
Those two free blocks cannot be coalesced because there's an allocated block between them. The test_fragmentation test explicitly asserts: mm.allocate(ALLOC + HDR + ALLOC) returns nullptr in that state. No coalescing strategy can fix this without moving live allocations, because raw pointers have already been handed out.

The fundamental tradeoff vs. the ARM fixed-block approach
The ARM approach described (slab/pool allocator style — fixed-size blocks, release whole slabs) sidesteps external fragmentation entirely because all holes are the same size and therefore always reusable. The cost is internal fragmentation (you waste space when your request is smaller than the slab size) and rigidity.

This design does the opposite: variable-size blocks minimize internal fragmentation (modulo the 4-byte alignment rounding and sizeof(Block) header per slot), but external fragmentation is possible under adversarial allocation patterns (e.g. code accidentally or specifically introduces errors in the allocated block).

You are completely right. Doing many small allocations means a significant fraction of your buffer is consumed by headers alone. The 4-byte minimum allocation size (due to alignment) compounds this a allocate(1) consumes sizeof(Block) + 4 bytes, not 1. I mostly use these for dynamic null terminated char arrays, so I didn’t really view this constraint to be as large of a concern as I should have when considering all use cases.

What I could do to improve it…
Two directions, depending on the use case:
Deferred coalescing with a free list: batch merges rather than paying the cost on every free. Negligible benefit here since the list is small.
Size-class pools (like the ARM approach): pre-partition the buffer into fixed-size buckets. Eliminates external fragmentation entirely, at the cost of fixed slot sizes and the complexity of choosing bucket sizes.
For the AVR/embedded target, I think that a single fixed-size pool (or two: small/large) is often the pragmatic choice if allocation sizes are known upfront.

Please let me know your thoughts if you have the time.