nanovms / nanos Goto Github PK
View Code? Open in Web Editor NEWA kernel designed to run one and only one application in a virtualized environment
Home Page: https://nanos.org
License: Apache License 2.0
A kernel designed to run one and only one application in a virtualized environment
Home Page: https://nanos.org
License: Apache License 2.0
it looks* like this probably uses the gs convention, and it is calling a thread state related syscall on main startup. so look at it, and in particular add gs/fs save restore to the generic trap/context machinery
how embarrassing, the length of the file is being reported as the maximum covered extent...but
files actually have arbitrary byte length. add a metadata property for the actual written
length of the file
startup frame doesn't result in executable seeing any entries
fill in interaction with epoll(), blocking completion, downcall to allocate lwip state and opcall to handle connect, timeout, and explicit error, feed unix errno up appropriately
there are tens of little regions floating around, with no real guarantee that they are disjoint.
keep a global map of virtual allocations with some semantic annotations.
use this to generate a proper /proc/self/maps which pthreads is using to locate
the stack
can also add a debugging aid - what was this address mapped for
On a fresh master tree:
$ qemu-system-x86_64 -version
QEMU emulator version 2.8.1(Debian 1:2.8+dfsg-6+deb9u4)
Copyright (c) 2003-2016 Fabrice Bellard and the QEMU Project developers
$ make run-nokvm
make -f image.mk image
make[1]: warning: jobserver unavailable: using -j1. Add '+' to parent make rule.
make[1]: Entering directory '/share/src/uniboot-test2'
cd boot ; make
make[2]: Entering directory '/share/src/uniboot-test2/boot'
make[2]: Nothing to be done for 'all'.
make[2]: Leaving directory '/share/src/uniboot-test2/boot'
cd mkfs ; make
make[2]: Entering directory '/share/src/uniboot-test2/mkfs'
make[2]: Nothing to be done for 'all'.
make[2]: Leaving directory '/share/src/uniboot-test2/mkfs'
cd stage3 ; make
make[2]: Entering directory '/share/src/uniboot-test2/stage3'
make[2]: Nothing to be done for 'all'.
make[2]: Leaving directory '/share/src/uniboot-test2/stage3'
cd examples ; make
make[2]: Entering directory '/share/src/uniboot-test2/examples'
make[2]: Nothing to be done for 'all'.
make[2]: Leaving directory '/share/src/uniboot-test2/examples'
make[1]: Leaving directory '/share/src/uniboot-test2'
cp image image2
qemu-system-x86_64 -boot c -drive file=image,format=raw,if=ide -nographic -m 2G -device isa-debug-exit -drive file=image2,format=raw,if=virtio
create fs
kernel complete
pages heap: 0000000000225000, length 00000000002f8000
physical memory:
base 0000000000800000, length 000000007f600000
FATAL ERROR:system clock is inaccessible
Makefile:46: recipe for target 'run-nokvm' failed
make: [run-nokvm] Error 1 (ignored)
it should be possible to provide a functional backing to fill in the contents of a tuple on demand, this allows things like /proc and /dev in stage 1, but is critical for stage2
In a fresh filesystem branch:
wjhun@tiger:/share/src/uniboot$ cc --version
cc (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
wjhun@tiger:/share/src/uniboot$ make
make -f image.mk image
make[1]: warning: jobserver unavailable: using -j1. Add '+' to parent make rule.
make[1]: Entering directory '/share/src/uniboot'
cd boot ; make
make[2]: Entering directory '/share/src/uniboot/boot'
nasm -felf service32.s
cc -std=c99 /share/src/uniboot/boot/../runtime/contgen.c -g -o /share/src/uniboot/boot/../runtime/contgen
/share/src/uniboot/boot/../runtime/contgen 10 10 > /share/src/uniboot/boot/../runtime/closure_templates.h
cc -m32 -O -fno-stack-protector -include def32.h -I/share/src/uniboot/boot/../x86_64 -I/share/src/uniboot/boot/../runtime -I/share/src/uniboot/boot/../tfs -I. -I../runtime stage2.c -c
cc -m32 -O -fno-stack-protector -include def32.h -I/share/src/uniboot/boot/../x86_64 -I/share/src/uniboot/boot/../runtime -I/share/src/uniboot/boot/../tfs -I. -I../runtime /share/src/uniboot/boot/../x86_64/serial.c -c
cc -m32 -O -fno-stack-protector -include def32.h -I/share/src/uniboot/boot/../x86_64 -I/share/src/uniboot/boot/../runtime -I/share/src/uniboot/boot/../tfs -I. -I../runtime /share/src/uniboot/boot/../x86_64/page.c -c
cc -m32 -O -fno-stack-protector -include def32.h -I/share/src/uniboot/boot/../x86_64 -I/share/src/uniboot/boot/../runtime -I/share/src/uniboot/boot/../tfs -I. -I../runtime /share/src/uniboot/boot/../x86_64/elf.c -c
cc -m32 -O -fno-stack-protector -include def32.h -I/share/src/uniboot/boot/../x86_64 -I/share/src/uniboot/boot/../runtime -I/share/src/uniboot/boot/../tfs -I. -I../runtime /share/src/uniboot/boot/../runtime/heap/zero_wrap.c -c
cc -m32 -O -fno-stack-protector -include def32.h -I/share/src/uniboot/boot/../x86_64 -I/share/src/uniboot/boot/../runtime -I/share/src/uniboot/boot/../tfs -I. -I../runtime /share/src/uniboot/boot/../x86_64/kvm_platform.c -c
cc -m32 -O -fno-stack-protector -include def32.h -I/share/src/uniboot/boot/../x86_64 -I/share/src/uniboot/boot/../runtime -I/share/src/uniboot/boot/../tfs -I. -I../runtime /share/src/uniboot/boot/../tfs/tlog.c -c
cc -m32 -O -fno-stack-protector -include def32.h -I/share/src/uniboot/boot/../x86_64 -I/share/src/uniboot/boot/../runtime -I/share/src/uniboot/boot/../tfs -I. -I../runtime /share/src/uniboot/boot/../tfs/tfs.c -c
In file included from /share/src/uniboot/boot/../runtime/runtime.h:126:0,
from /share/src/uniboot/boot/../tfs/tfs_internal.h:1,
from /share/src/uniboot/boot/../tfs/tfs.c:1:
/share/src/uniboot/boot/../tfs/tfs.c: In function ‘fs_read_extent’:
/share/src/uniboot/boot/../tfs/tfs.c:28:85: warning: passing argument 5 of ‘fs->r’ from incompatible pointer type [-Wincompatible-pointer-types]
apply(fs->r, buffer_ref(target, i.start), range_span(i), u64_from_pointer(val), f);
^
/share/src/uniboot/boot/../runtime/closure.h:5:40: note: in definition of macro ‘apply’
#define apply(__c, ...) (__c)(__c, ## VA_ARGS)
^~~~~~~~~~~
/share/src/uniboot/boot/../tfs/tfs.c:28:85: note: expected ‘status_length_handler {aka void ()(void *, long long unsigned int, struct table *)}’ but argument is of type ‘status_handler {aka void ()(void *, struct table )}’
apply(fs->r, buffer_ref(target, i.start), range_span(i), u64_from_pointer(val), f);
^
/share/src/uniboot/boot/../runtime/closure.h:5:40: note: in definition of macro ‘apply’
#define apply(__c, ...) (__c)(__c, ## VA_ARGS)
^~~~~~~~~~~
cc -m32 -O -fno-stack-protector -include def32.h -I/share/src/uniboot/boot/../x86_64 -I/share/src/uniboot/boot/../runtime -I/share/src/uniboot/boot/../tfs -I. -I../runtime /share/src/uniboot/boot/../tfs/merge.c -c
cc -m32 -O -fno-stack-protector -include def32.h -I/share/src/uniboot/boot/../x86_64 -I/share/src/uniboot/boot/../runtime -I/share/src/uniboot/boot/../tfs -I. -I../runtime /share/src/uniboot/boot/../runtime/table.c -c
cc -m32 -O -fno-stack-protector -include def32.h -I/share/src/uniboot/boot/../x86_64 -I/share/src/uniboot/boot/../runtime -I/share/src/uniboot/boot/../tfs -I. -I../runtime /share/src/uniboot/boot/../runtime/buffer.c -c
cc -m32 -O -fno-stack-protector -include def32.h -I/share/src/uniboot/boot/../x86_64 -I/share/src/uniboot/boot/../runtime -I/share/src/uniboot/boot/../tfs -I. -I../runtime /share/src/uniboot/boot/../runtime/format.c -c
cc -m32 -O -fno-stack-protector -include def32.h -I/share/src/uniboot/boot/../x86_64 -I/share/src/uniboot/boot/../runtime -I/share/src/uniboot/boot/../tfs -I. -I../runtime /share/src/uniboot/boot/../runtime/heap/id.c -c
cc -m32 -O -fno-stack-protector -include def32.h -I/share/src/uniboot/boot/../x86_64 -I/share/src/uniboot/boot/../runtime -I/share/src/uniboot/boot/../tfs -I. -I../runtime /share/src/uniboot/boot/../runtime/symbol.c -c
cc -m32 -O -fno-stack-protector -include def32.h -I/share/src/uniboot/boot/../x86_64 -I/share/src/uniboot/boot/../runtime -I/share/src/uniboot/boot/../tfs -I. -I../runtime /share/src/uniboot/boot/../runtime/heap/rolling.c -c
cc -m32 -O -fno-stack-protector -include def32.h -I/share/src/uniboot/boot/../x86_64 -I/share/src/uniboot/boot/../runtime -I/share/src/uniboot/boot/../tfs -I. -I../runtime /share/src/uniboot/boot/../runtime/tuple.c -c
cc -m32 -O -fno-stack-protector -include def32.h -I/share/src/uniboot/boot/../x86_64 -I/share/src/uniboot/boot/../runtime -I/share/src/uniboot/boot/../tfs -I. -I../runtime /share/src/uniboot/boot/../runtime/random.c -c
cc -m32 -O -fno-stack-protector -include def32.h -I/share/src/uniboot/boot/../x86_64 -I/share/src/uniboot/boot/../runtime -I/share/src/uniboot/boot/../tfs -I. -I../runtime /share/src/uniboot/boot/../runtime/rtrie.c -c
cc -m32 -O -fno-stack-protector -include def32.h -I/share/src/uniboot/boot/../x86_64 -I/share/src/uniboot/boot/../runtime -I/share/src/uniboot/boot/../tfs -I. -I../runtime /share/src/uniboot/boot/../runtime/runtime_init.c -c
cc -m32 -O -fno-stack-protector -include def32.h -I/share/src/uniboot/boot/../x86_64 -I/share/src/uniboot/boot/../runtime -I/share/src/uniboot/boot/../tfs -I. -I../runtime /share/src/uniboot/boot/../runtime/extra_prints.c -c
cc -m32 -O -fno-stack-protector -include def32.h -I/share/src/uniboot/boot/../x86_64 -I/share/src/uniboot/boot/../runtime -I/share/src/uniboot/boot/../tfs -I. -I../runtime /share/src/uniboot/boot/../runtime/heap/debug_heap.c -c
ld -T linker_script -e _start service32.o stage2.o serial.o page.o elf.o zero_wrap.o kvm_platform.o tlog.o tfs.o merge.o table.o buffer.o format.o id.o symbol.o rolling.o tuple.o random.o rtrie.o runtime_init.o extra_prints.o debug_heap.o -o stage2.elf
strip stage2.elf -o stage2.strip
objcopy -S -O binary stage2.strip stage2
dd if=stage2 of=stage2.pad bs=512 conv=sync
81+1 records in
82+0 records out
41984 bytes (42 kB, 41 KiB) copied, 0.000657015 s, 63.9 MB/s
nasm -l stage1.lst -dSTAGE1SIZE=512 -dSTAGE2SIZE=41984 stage1.s -o stage1
cat stage1 stage2.pad > boot
make[2]: Leaving directory '/share/src/uniboot/boot'
cd mkfs ; make
make[2]: Entering directory '/share/src/uniboot/mkfs'
cc -g -c -include def64.h -I/share/src/uniboot/mkfs/../runtime -I/share/src/uniboot/mkfs/../x86_64 -I/share/src/uniboot/mkfs/../tfs mkfs.c
In file included from :32:0:
/share/src/uniboot/mkfs/../x86_64/def64.h: In function ‘format_pointer’:
/share/src/uniboot/mkfs/../x86_64/def64.h:48:5: internal compiler error: in build_va_arg, at c-family/c-common.c:5812
u64 x = varg(a, u64);
^~~
Please submit a full bug report,
with preprocessed source if appropriate.
See file:///usr/share/doc/gcc-6/README.Bugs for instructions.
Makefile:12: recipe for target 'mkfs.o' failed
make[2]: *** [mkfs.o] Error 1
make[2]: Leaving directory '/share/src/uniboot/mkfs'
image.mk:8: recipe for target 'mkfs/mkfs' failed
make[1]: *** [mkfs/mkfs] Error 2
make[1]: Leaving directory '/share/src/uniboot'
Makefile:8: recipe for target 'image' failed
make: *** [image] Error 2
wjhun@tiger:/share/src/uniboot$
Probably a good thing to fix along with header deps. Seems that including the runtime Makefile in various parts of the build leads to contention.
Solution should be to build contgen once for the whole tree.
$ make -j8
make -f image.mk image
cd test ; make
make[1]: warning: jobserver unavailable: using -j1. Add '+' to parent make rule.
make[1]: warning: jobserver unavailable: using -j1. Add '+' to parent make rule.
make[1]: Entering directory '/share/src/uniboot-memory2-test'
cd boot ; make
make[1]: Entering directory '/share/src/uniboot-memory2-test/test'
cc -std=c99 /share/src/uniboot-memory2-test/test/../runtime/contgen.c -g -o /share/src/uniboot-memory2-test/test/../runtime/contgen
make[2]: Entering directory '/share/src/uniboot-memory2-test/boot'
nasm -felf service32.s
cc -std=c99 /share/src/uniboot-memory2-test/boot/../runtime/contgen.c -g -o /share/src/uniboot-memory2-test/boot/../runtime/contgen
/share/src/uniboot-memory2-test/test/../runtime/contgen 10 10 > /share/src/uniboot-memory2-test/test/../runtime/closure_templates.h
/bin/sh: 1: /share/src/uniboot-memory2-test/test/../runtime/contgen: Text file busy
/share/src/uniboot-memory2-test/test/../runtime/Makefile:9: recipe for target '/share/src/uniboot-memory2-test/test/../runtime/closure_templates.h' failed
make[1]: *** [/share/src/uniboot-memory2-test/test/../runtime/closure_templates.h] Error 2
make[1]: Leaving directory '/share/src/uniboot-memory2-test/test'
Makefile:14: recipe for target 'test' failed
make: *** [test] Error 2
make: *** Waiting for unfinished jobs....
there is a comment at the end of netsyscall.c:read_complete
// tcp_recved() to move the receive window
gdb input does call this function after consuming the payload, but there is a comment
there
// not necessarily
verify that this is the right thing to do and do it
intitially we treat an mmap on a file as a read...we should (for some value of should),
trying to register 256 file descriptors with epoll:
zero (length=4096, x=0x1001a0000) at ../runtime/runtime.h:61
61 ((u8 *)x)[i] = 0;
(gdb) bt
#0 zero (length=4096, x=0x1001a0000) at ../runtime/runtime.h:61
#1 resize_table (buckets=512, z=0x1000580e3) at ../runtime/table.c:66
#2 table_set (z=0x1000580e3, c=c@entry=0x105, v=0x10019cc90) at ../runtime/table.c:120
#3 0x000000000f01b9cb in epoll_ctl (epfd=, op=, fd=261, event=0x500159c40) at ../unix/poll.c:122
#4 0x000000000f01906a in syscall_debug () at ../unix/unix.c:120
#5 0x000000000f013f34 in syscall_enter ()
multiplex on the socket proto, consider just filling out the msg variants at the same time
instead it takes the passed status x, and returns (x<<1)|1 as the process status
once #18 is done, wire that up into gdb.
this looks like it will let us do symbolic resolution without loading the objects into gdb
current clock support uses the kvm clock to calibrate rdtsc. if that fails, things proceed under the assumption that the clock scaling factor is reasonable when in fact it is not. a) throw an error b) implement an alternative normalization scheme (hpet?)
we look for the e820 region, but don't try to pass it to the user. it contains several segments, the most important being the ~4G before the 'pci gap' and what should be flat memory afterwards.
we could most likely move everything out of the pci gap, but we'd have to adjust the mtrrs and its really not worth it.
so add multi-segement reporting, and look at the 64 bit e820 extensions...or* maybe the virtio balloon interface lets just get the initial memory status - that would be a lot cleaner
I ran into a few out-of-sync builds from objects not being updated after header file changes.
Of possible interest: http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/
with independent allocators. they should be constructively disjoint, but someone should really stop
the process from calling mmap anon with a specified address thats already allocated
(i'm looking at you #13)
Now with improved memory re-use, the kernel is outlasting network_test:
Could be we're hitting a limit with brk?
(gdb) r 192.168.42.76:8080
Starting program: /share/src/uniboot-memory-lwip/test/network_test 192.168.42.76:8080
Program received signal SIGSEGV, Segmentation fault.
0x0000555555557ff4 in zero (x=0xffffffffffffffff, length=32) at /share/src/uniboot-memory-lwip/test/../runtime/runtime.h:63
63 ((u8 *)x)[i] = 0;
1: x/i $pc
=> 0x555555557ff4 <zero+34>: movb $0x0,(%rax)
(gdb) bt
#0 0x0000555555557ff4 in zero (x=0xffffffffffffffff, length=32) at /share/src/uniboot-memory-lwip/test/../runtime/runtime.h:63
#1 0x0000555555558995 in table_set (z=0x2000003ffd40, c=0x100000000020, v=0x555556e290b0) at /share/src/uniboot-memory-lwip/test/../runtime/table.c:108
#2 0x0000555555556a99 in http_recv (p=0x555556e25340, b=0x555556e28db0) at http.c:115
#3 0x00005555555567aa in _apply_http_recv (z=0x555556e253f0, r0=0x555556e28db0) at http.c:72
#4 0x000055555555775d in connection_input (h=0x555555770010, f=6, e=3, p=0x555556e253f0) at /share/src/uniboot-memory-lwip/test/../unix_process/socket_user.c:82
#5 0x0000555555557659 in _apply_connection_input (z=0x555556e25410) at /share/src/uniboot-memory-lwip/test/../unix_process/socket_user.c:71
#6 0x0000555555557ec6 in epoll_spin (e=3) at /share/src/uniboot-memory-lwip/test/../unix_process/socket_user.c:168
#7 0x000055555555593c in main (argc=2, argv=0x7fffffffdd68) at network_test.c:67
(gdb) info reg
rax 0xffffffffffffffff -1
rbx 0x100000000020 17592186044448
rcx 0x5 5
rdx 0x0 0
rsi 0x20 32
rdi 0xffffffffffffffff -1
rbp 0x7fffffffda20 0x7fffffffda20
rsp 0x7fffffffda20 0x7fffffffda20
r8 0x555556e29040 93825018269760
r9 0x0 0
r10 0xffffffff 4294967295
r11 0x246 582
r12 0x555555554be0 93824992234464
r13 0x7fffffffdd60 140737488346464
r14 0x0 0
r15 0x0 0
rip 0x555555557ff4 0x555555557ff4 <zero+34>
eflags 0x10286 [ PF SF IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) disas /s
[...]
0x0000555555558945 <+312>: test %rax,%rax
0x0000555555558948 <+315>: jne 0x555555558873 <table_set+102>
0x000055555555894e <+321>: cmpq $0x0,-0x58(%rbp)
0x0000555555558953 <+326>: je 0x555555558a17 <table_set+522>
0x0000555555558959 <+332>: movq $0x20,-0x30(%rbp)
0x0000555555558961 <+340>: mov -0x10(%rbp),%rax
0x0000555555558965 <+344>: mov (%rax),%rax
0x0000555555558968 <+347>: mov (%rax),%rax
0x000055555555896b <+350>: mov -0x10(%rbp),%rdx
0x000055555555896f <+354>: mov (%rdx),%rdx
0x0000555555558972 <+357>: mov -0x30(%rbp),%rcx
0x0000555555558976 <+361>: mov %rcx,%rsi
0x0000555555558979 <+364>: mov %rdx,%rdi
0x000055555555897c <+367>: callq *%rax
0x000055555555897e <+369>: mov %rax,-0x38(%rbp)
0x0000555555558982 <+373>: mov -0x30(%rbp),%rdx
0x0000555555558986 <+377>: mov -0x38(%rbp),%rax
0x000055555555898a <+381>: mov %rdx,%rsi
0x000055555555898d <+384>: mov %rax,%rdi
0x0000555555558990 <+387>: callq 0x555555557fd2 <zero>
=> 0x0000555555558995 <+392>: mov -0x38(%rbp),%rax
0x0000555555558999 <+396>: mov %rax,-0x40(%rbp)
0x000055555555899d <+400>: cmpq $0xffffffffffffffff,-0x40(%rbp)
0x00005555555589a2 <+405>: jne 0x5555555589b5 <table_set+424>
the long term solution for this issue is to fold stage2 into stage1 so the load exactly match what is needed for the segments.
however, since the extended read call under qemu fills it what it can before returning an error, and the elf image defines the length of the 'drive', we can really just read contiguously until error. need to fix the reporting of the allocated base to stage2 and the application
right now the elf loader kind of hopes that there are no address conflicts with anyone else, this is easy enough to track and should be
mono interprets argv[0] as the first arg. is this a libc thing or a staring frame thing
currently tfs doesn't handle adding additional log segments
one file for the bios boot device and one for the virtio driver. that seems pretty
ridiculous, but the qemo options/config are all over the map, and I've wasted
alot of time trying to get a magic configuration that works. this would make it
easier to throw around and run images, but this might get mitigated by the
wrapper framework
need to come up with a filesystem api that allows for a union fs root with functional handlers
it uses atomics to manipulate the read and write pointers, but there is a race between allocating a slot and populating it, which could lead to the consumer reading trash
if the number of removals gets to be a sufficiently large ratio of the log space, the
kernel should start a background process to write the in-memory version
(where the creates and removal have already been reconciled) to new segments.
the root of the log should be (atomically) replaced with a single sector containg
a next record pointing to the new log. this clearly depends on #20
if the disk is exhausted, then it may be impossible to regain this space because of the
lack of working area.
look at using the lwip pool support or make a heap based pool
application builds shouldn't require a complicated makefile and parts of the lwip configuration. normalize so that the application build is presented with a single include tree and a small number of archive libraries to link to.
there clearly remains a race, much more pronounced or possibly exclusively manifest in qemu 2.5
symptoms include silently ignored transmit request, and unwillingness to post receive interrupts.
most likely an issue with order of initialization, but could really be anything
right now we are exitting on the empty runqueue condition (deadlock). clearly a ball is getting dropped in futex-world
identity isn't always convenient, but its not clear what the best scheme is to virtually address the ptes....particularily given the recurrence problem. maybe a large-ish fixed offset pool
its only populating files at the top level
oh, and have do a mkdir please, and also add command line help
the lapic (or whatever time resource) should be configured to deliver the next interrupt at the correct time to wake up the next timer queue entry
right now it polls at 50ms, which is both wasteful and inaccurate
eric broke this two months ago, constructed an elaborate plan to fix it, and didn't complete the work. should just be a case of reading the file and mapping it, and then running ld.so through its paces
there is almost certainly an issue thats being masked by the bloated default assembly
no reason people should have to suffer tracking down dynamic dependencies
yuri@eclair:~/uniboot$ ldd examples/hw
linux-vdso.so.1 => (0x00007ffe0e320000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3a6c560000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3a6c92a000)
this is only important if we change a mapping, which we should rarely if ever do. this becomes more important in the multiprocessor case, since telling everyone to flush is expensive
amd64 also has a per-page tlb flush instruction invlpg
[find the relevant version numbers, link to the qemu bug, and discuss the mitigation options]
minor enhancement for debugging. one more step past this would get us a proper backtrace.
initializations would then have explicit dependencies, and allow for fully link-time modularization of things like drivers, etc
finish the work in the tuple parser to allow for infix operators that make it easier to talk about
filesystem paths, and finish/fix quoted strings. also reinstitute the functionality of having
mkfs be able to use immediate file contents if it doesn't already.
plumbing isn't there to run multiple event types over poll notify
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.