-
Notifications
You must be signed in to change notification settings - Fork 1
/
txt2.txt
240 lines (207 loc) · 7.06 KB
/
txt2.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
There're
1.c
1.h
2.c
gcc -o a.out 1.c 2.c
There're 4 stadies:
1)Preprocessing-->Source C code (text expandings)
2)Compilation-->Macroassembler code
3)Assembler-->Object file(binary file you cannot execute because
some vars and some jumps don't have right adresses)
4)Linker(Russian:Komponovshchik)-->Binary executable file
gcc -c -o 1.o 1.c
gcc -c -o 2.o 2.c
gcc -o a.out 2.o 1.o
//Order is important
This is better because if we'd changed 1.c, we must execute just 2/3 of work.
So for big modules we will get a lot of profit.
This is gmake in GNU
nmake in Microsoft
They both makes this: we have a dependence, because we have a goal and
prerecvizites. And we have an rules goal<-->prerecvizites. They're complex
enough.
all: a.out
a.out: 1.o 2.o
<TAB>gcc -o a.out 1.o 2.o
1.o: 1.c
<TAB>gcc -c -o 1.o 1.c
<TAB>#May be something else
<TAB>#And more...
2.o: 2.c
<TAB>gcc -c -o 2.o 2.c
1.o 2.o: 1.h
clean:
<TAB>rm -rf *.o a.out
We can declare goals to execute ALWAYS!!!
Nothing is harcored!!!
.PHONY: all clean
We can use
a.out: 1.o 2.o
<TAB>gcc -o $@ $^
//And you have a right not to write this rule
%.o: %.c //%==[1,2]
<TAB>$(CC) $(CFLAGS) -c -o $@ $<
-MD flag will tell you about *.h dependencies
-include *.d //- sign to ignore errors on the first time
gmake/make -p
-g16 //cores*threads*2
_______________________________________________________________________________
Check that Valgrind doesn't return errors.
Don't use ? . Use if and else.
Must be one/zero operator on one line.
My test must cover >= 96% of code. Use gcov. Must be some flags.
Allocate can return error because of ulimit or replacing of malloc.
Use do {...} while(0)
BUILD_BUG_ON
We have some magic useful func:
void log( levlg, const char* format, ...);
It must not have side effect.
So we use macrodefinitions:
#define log(level, format, ...) \
do \
{\
if (level > current_lelel)\
{\
do_log(level, format, ...);\
}\
}
int f()
{
static int a;
return ++a;
}
int main()
{
printf("%d %d\n", f(), f());
return 0;
} ----> we don't know what will be printed
Use -Wall -Werror
_______________________________________________________________________________
Some applied thing - SVC
There's interesting program diff -up
1.o.old 1.c
--- 1.c.old
+++ 1.c
@@ -347,7 +426,8 @@ void handler
printf("%d\n");
printf("%d\n");
- i=5;
+ i=6;
+ j=3;
printf( );
printf( );
@@
There's patch utilite to apply a difference
The -p{NUM} deletes {NUM} folders in names
git
_______________________________________________________________________________
We need to get a connetion between two computers. There's some special
primitive - socket - duplex FIFO.
This is two pipes connected with one descriptor. If we talk about various
machines, we talk about PF_INET.
PF_UNIX is faster but only one computer.
Socket can be 'datagrammed' or streams.
In order to get a connection socket that get and initialize connection, are
initialized in different way.
Get:
sk = socket(PF_INET, SOCK_STREAM,0);
listen(sk, 255);
bind(sk, sock_addr, sizeof(sock_addr));
sk2 = accept(sk, addr, sizeof(addr));
read(sk2);
write(sk2);
close(sk2);
i.e.
while(1) {
sk2 = accept(sk);
fork();
} //this is standart pattern
Initialize:
sk = socket(PF_INET, SOCK_STREAM, 0);
connect(sk, addr, sizeof(add));
struct sockaddr addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(4000);
addr.sin_addr.st_addr = htonl(INADDR_ANY);
//this must be after listen()
Magic addresses:
127.0.0.1 -> 0x7F000001
=======================================UDP=====================================
sk = socket(RF_INET, SOCK_DGRAM,0);
bind();
revc/recvfrom/read
sk = socket();
1. connect
write
2. sendto
int x = 1;
setsockopt(sk, SOL_SOCKET, SO_BROADCAST, !x);
255.255.255.255
The idea for our program: we have a razdatchik and workers. Worker must
create UDP socket and wait on it. Razdatchik must send UDP-message to all
workers(make broadcast). Workers say: I'm here. So razdatchik knows all IP's of
workers and can send tasks.
_______________________________________________________________________________
How to debug this thing?
We must sniff the packets.
tcpdump
wireshark
We have payload, TCP header, IP header, Ethernet header etc.
In Ethernet header we have address of sender's and receiver's cards (local).
MAC SRC and MAC DST. IP, MAC.
In kernel we have two thins: (route table) and (ARP cache)==(Linking MAC to IP
addresses).
Route table tells us where send to (only next one, not the end).
We can see route table in `ip rout list` or `ip r l`.
We can add route by two ways - ip r a 192.168.1.0/24 dev eth 0
or - gv 192.168.1.1
ip route get
192.168.2.1 &
255.255.224.0
192.168.0.0 - the IP of our network
192.168.0.0/20 <- the 20 1s in the beginning of mask
arp -n
What we have more on IP level?
In IP header we have IP SRC and IP DST, CRC [of IP header only, because of
performance], TTL [time to live], frag, proto [TCP or UDP]
In TCP header: SRC PORT, DST PORT. In real world in TCP mustn't be
IP fragmentation. TCP delivers semantics of two pipes - reliable
connetion. CRC of all packet and TCP header. We numerate bytes, so
we have two numbers: len and seq (the order of 1st byte in packet).
We must ACK (acknowledgment, the data that I received). And flags.
Flags: SYN, FIN, RST, ACK;
And retransmit count;
How to create connection? Send packet with SYN. In answer SYN, ACK; Then: ACK;
To destroy: -->FIN, <-- ACK, <-- FIN, --> ACK.
_______________________________________________________________________________
Why is it reliable?
How to resend data? We write usual terminal. In order to right work of system
we need to send symbol at once. But send header on every symbol is expensive.
Simple thing: Nagle algorithm. If I have no packets to send I can send just 1
symbol. After this we wait ~100 ms or accept from server.
The right size of payload is needed. There's special interface PNTU discovery.
When we send SYN packet all routes refresh field (max size of packet).
So we escape IP fragmentation.
When to resend packet? Timeouts grows with exponent. We need ~260 Mbit buffer
to send data to Moon.
On hardware we can count checksums.
Latch Receive Offload.
Interrupts not on every packet.
One processor can get just 6Gib/s. So we must give job to every core.
_______________________________________________________________________________
About ill.
We have some problems with disk:
1.We can do just 100-150 writes/sec
2.When we write we write not only data but metadata.
We can turn off page cache with O_DIRECT
On SSD we cannot use all stream (>=500 MByte/s) with one thread.
So we must write in it with several stream.
So we cannot use write, we use pwrite. Or pwritev(not in MacOS).
We have libio. We start IO operation in our context. This works only with
O_DIRECT.
We have EVENT_FD. We have 64-bit value. When it's 0, we block until it won't
be 0. It (libio) has two syscalls - submit and getevents.
_______________________________________________________________________________
About memory.
We need to free memory.
There's a out-of-memory killer.