
рдореИрдВ рдПрдХ рдЦрд┐рд▓реМрдирд╛ рдУрдПрд╕ (рдкрд┐рдЫрд▓реА рдкреЛрд╕реНрдЯ:
рдПрдХ ,
рджреЛ ,
рддреАрди ) рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмреНрд▓реЙрдЧ рдЬрд╛рд░реА рд░рдЦрддрд╛ рд╣реВрдВред рдХреЛрдбрд┐рдВрдЧ рдореЗрдВ рд╡рд┐рд░рд╛рдо рдХреЗ рдмрд╛рдж (рдордИ рдХреА рдЫреБрдЯреНрдЯрд┐рдпрд╛рдВ, рдЖрдЦрд┐рд░рдХрд╛рд░), рдореИрдВ рдХрд╛рдо рдХрд░рдирд╛ рдЬрд╛рд░реА рд░рдЦрддрд╛ рд╣реВрдВред рдкреАрд╕реАрдЖрдИ рдмрд╕ рдХреЗ рдПрдХ рд╕реНрдХреИрди рдХреЛ рд╕реНрдХреЗрдЪ рдХрд┐рдпрд╛ред SATA рдирд┐рдпрдВрддреНрд░рдХ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрд╕ рдЪреАрдЬ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА: рдЕрдЧрд▓реА рдЪреАрдЬ рдЬреЛ рдореИрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рд╡рд╣ рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдбрд┐рд╕реНрдХ рдбреНрд░рд╛рдЗрд╡рд░ рд╣реИред рдпрд╣ рдЖрдкрдХреЛ рдкрддрд╛ рд╕реНрдерд╛рди рдкрд░ рд░реАрдб-рдУрдирд▓реА рдореЗрдореЛрд░реА рдХреЗ рдкреНрд░рдХреНрд╖реЗрдкрдг рдХреЗ рд╕рд╛рде рдкреНрд░рдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдЧрд╛ (рд╕реНрд╡реИрдк рдЕрдкрдиреЗ рддрд╛рд░реНрдХрд┐рдХ рдЕрдВрдд рддрдХ рд▓рд╛рдпрд╛ рдЧрдпрд╛)ред рдЗрд╕ рдмреАрдЪ, рдореИрдВ рдореНрдпреВрдЯреЗрдХреНрд╕ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдирд╛ рдЪрд╛рд╣реВрдВрдЧрд╛ред
рдореНрдпреВрдЯреЗрдХреНрд╕ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП (
src / Sync.h рдФрд░
src / sync.c рдореЗрдВ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдФрд░ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд) рджреЛ рдкрд┐рдЫрд▓реЗ рдкрджреЛрдВ рдореЗрдВ рд╡рд░реНрдгрд┐рдд рдореМрдЬреВрджрд╛ рдЕрдиреБрд╕реВрдЪрдХ рдХреЛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред рдПрдХ рдореНрдпреВрдЯреЗрдХреНрд╕ рдХреЛ рдЗрд╕рдХреЗ рдХреЗрд╡рд▓ рджреЛ рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдмрдирд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ: рдПрдХ рд╕реНрдЯреНрд░реАрдо рд╢реБрд░реВ рдХрд░реЗрдВ рдФрд░ рд░реЛрдХреЗрдВ (рджреЗрдЦреЗрдВ
src / schedule.h )ред
struct mutex { struct __mutex_node *head, *tail; struct spinlock mlock, ilock; }; static inline void create_mutex(struct mutex *mutex) { mutex->head = mutex->tail = NULL; create_spinlock(&mutex->mlock); create_spinlock(&mutex->ilock); }
рдореЗрд░реЗ рдореНрдпреВрдЯреЗрдХреНрд╕ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдореЗрдВ рджреЛ рд╕реНрдкрд┐рдирд▓реЙрдХ рдФрд░ рд╕реНрд▓реАрдкрд┐рдВрдЧ рдереНрд░реЗрдбреНрд╕ рдХреА рдПрдХ рдХрддрд╛рд░ рд╢рд╛рдорд┐рд▓ рд╣реИред рдкрд╣рд▓рд╛ рд╕реНрдкрд┐рдирд▓реЙрдХ (рдкреНрд▓реЙрдХ) рд╕рдВрд░рдХреНрд╖рд┐рдд рдореНрдпреВрдЯреЗрдХреНрд╕ рд╕рдВрд╕рд╛рдзрди рддрдХ рдкрд╣реБрдВрдЪ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИ, рдЕрд░реНрдерд╛рддреНред рдпрджрд┐ рдХреЗрд╡рд▓ рдореНрдпреВрдЯреЗрдХреНрд╕ рдХреЛ рд╣реА рдХреИрдкреНрдЪрд░ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рддреЛ рдЙрд╕реЗ рдХреИрдкреНрдЪрд░ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рджреВрд╕рд░рд╛ рд╕реНрдкрд┐рдирд▓реЙрдХ (рдЗрд▓реЙрдХ) рдПрдХ рд╕рд╛рде рд╕рдВрд╢реЛрдзрди рд╕реЗ рдкреНрд░рддреАрдХреНрд╖рд╛ рдзрд╛рдЧреЗ рдХреА рдХрддрд╛рд░ рдХреА рд░рдХреНрд╖рд╛ рдХрд░рддрд╛ рд╣реИред
рддреЛ рдпрд╣ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ? рдЬрдм рдПрдХ рдзрд╛рдЧрд╛ рдореНрдпреВрдЯреЗрдХреНрд╕ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рддрд╛ рд╣реИ, рддреЛ рдпрд╣ рдПрди рдкреНрд░рдпрд╛рд╕ рдХрд░рдиреЗ рдкрд░, рдЭреБрдВрдб рдХреЛ рдкрдХрдбрд╝рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рддрд╛ рд╣реИред рдпрджрд┐ рд╡рд╣ рд╕рдлрд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдореНрдпреВрдЯреЗрдХреНрд╕ рдкрд░ рдХрдмреНрдЬрд╛ рдХрд░ рд▓рд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЕрдиреНрдпрдерд╛, рдЗрд╕реЗ рд╕реБрд░рдХреНрд╖рд┐рдд рд░реВрдк рд╕реЗ (рдпрд╛рдиреА рдЗрд▓реЙрдХ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ) рдЦреБрдж рдХреЛ рдЗрдВрддрдЬрд╛рд░ рдХреЗ рдзрд╛рдЧреЗ рдХреА рдХрддрд╛рд░ рдореЗрдВ рдЬреЛрдбрд╝рдирд╛ рдЪрд╛рд╣рд┐рдП рдФрд░ рд╕реЛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред
static inline err_code acquire_mutex(struct mutex *mutex) { extern err_code __sleep_in_mutex(struct mutex *mutex); if (!acquire_spinlock_int(&mutex->mlock, 1000)) return __sleep_in_mutex(mutex); return ERR_NONE; } struct __mutex_node { struct __mutex_node *next; thread_id id; }; INTERNAL err_code __sleep_in_mutex(struct mutex *mutex) { struct __mutex_node *node = NULL; bool acquired; acquire_spinlock(&mutex->ilock, 0); acquired = acquire_spinlock_int(&mutex->mlock, 1); if (!acquired) { node = alloc_block(&mutex_node_pool); if (node) { node->next = NULL; node->id = get_thread(); if (mutex->head) mutex->head->next = node; mutex->head = node; if (!mutex->tail) mutex->tail = node; pause_this_thread(&mutex->ilock); } } if (!node) release_spinlock(&mutex->ilock); return (acquired || node) ? ERR_NONE : ERR_OUT_OF_MEMORY; }
рдЙрдкрд░реЛрдХреНрдд рдХреЛрдб рдХреЛ рдХреБрдЫ рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:
1. ach_spinlock_int рдлрд╝рдВрдХреНрд╢рди ach_spinlock рдХреЗ рд╕рдорд╛рди рд╣реИ, рд╕рд┐рд╡рд╛рдп рдЗрд╕рдХреЗ рдХрд┐ рдЬрдм рддрдХ рд╕реНрдкрд┐рдирд▓реЙрдХ рдЬрд╛рд░реА рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИ рддрдм рддрдХ рдпрд╣ рдмрд╛рдзрд┐рдд рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред рдЭреБрдВрдб рдкрд░ рдХрдмреНрдЬрд╛ рдХрд░рддреЗ рд╕рдордп, рд╣рдо рд╡реНрдпрд╡рдзрд╛рдиреЛрдВ рдХреЛ рдирд┐рд╖реНрдХреНрд░рд┐рдп рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ - рдореНрдпреВрдЯреЗрдХреНрд╕ рдХреЗ рдорд╛рд▓рд┐рдХ рд╣реЛрдиреЗ рдореЗрдВ рд▓рдВрдмрд╛ рд╕рдордп рд▓рдЧ рд╕рдХрддрд╛ рд╣реИред рдПрдХ рдФрд░ рдмрд╛рдд рдпрд╣ рд╣реИ рдХрд┐ рдЬрдм рд╣рдо рдЖрдИрд▓реЙрдХ рдкрд░ рдХрдмреНрдЬрд╛ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рддреЛ рдХрддрд╛рд░ рдореЗрдВ рдПрдХ рдзрд╛рдЧрд╛ рдЬреЛрдбрд╝рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ - рдпрд╣ рдСрдкрд░реЗрд╢рди рдЬрд▓реНрджреА рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред
2. __sleep_in_mutex рдлрд╝рдВрдХреНрд╢рди рдХреА рдирд┐рдореНрди рдкрдВрдХреНрддрд┐ рдкрд╣рд▓реА рдирдЬрд╝рд░ рдореЗрдВ рд╕рдВрд╡реЗрджрдирд╣реАрди рд╣реИ:
acquired = acquire_spinlock_int(&mutex->mlock, 1);
рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдЬрдм рд╣рдо рдкрд╣рд▓реЗ рд╣реА рдЕрд╕рдлрд▓ рд╣реЛ рдЪреБрдХреЗ рд╣реИрдВ рддреЛ рдлрд┐рд░ рд╕реЗ рдХрддрд╛рдИ рдкрд░ рдХрдмреНрдЬрд╛ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХреНрдпреЛрдВ? рдлрд┐рд░, рдХрд┐ рдкрд╣рд▓реЗ рдкреНрд░рдпрд╛рд╕ рдФрд░ рдЗрд▓реЙрдХ рдкрд░ рдХрдмреНрдЬрд╛ рдХрд░рдиреЗ рдХреЗ рдмреАрдЪ, рдореНрдпреВрдЯреЗрдХреНрд╕ рдХреЗ рдорд╛рд▓рд┐рдХ рдЗрд╕реЗ рд╡рд╛рдкрд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рдХреЗрд╡рд▓ рдмрд╛рдж рдореЗрдВ рд╣рдорд╛рд░реА рдзрд╛рд░рд╛ рдПрдХ рдирд┐рдпреЛрдЬрди рдХреНрд╡рд╛рдВрдЯрдо рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдЧреАред рджреВрд╕рд░реЗ рдкреНрд░рдпрд╛рд╕ рдХреЗ рдмрд┐рдирд╛, рд╣рдо рдЦреБрдж рдХреЛ рдХрддрд╛рд░ рдореЗрдВ рдЬреЛрдбрд╝ рд▓реЗрдВрдЧреЗ рдФрд░ рд╣рдореЗрд╢рд╛ рдХреЗ рд▓рд┐рдП рд╕реЛ рдЬрд╛рдПрдВрдЧреЗред рдЗрд╕рд▓рд┐рдП, рдЗрд▓реЙрдХ рдкрд░ рдХрдмреНрдЬрд╛ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рдлрд┐рд░ рд╕реЗ рдЬрд╛рдВрдЪ рдХрд░рдирд╛ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ (рдореНрдпреВрдЯреЗрдХреНрд╕ рдХреЗ рдорд╛рд▓рд┐рдХ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдЗрд╕реЗ рд▓реМрдЯрдиреЗ рдкрд░ рдХрдмреНрдЬрд╛ рдХрд░ рд▓реЗрдВрдЧреЗ)ред
3. рдЖрдмрдВрдЯрд┐рдд_рдмреНрд▓реЙрдХ рдФрд░ рдлреНрд░реА_рдмреНрд▓реЙрдХ рдлрд╝рдВрдХреНрд╢рди рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдЖрдХрд╛рд░ рдХреЗ рдкреВрд░реНрд╡-рдЖрд╡рдВрдЯрд┐рдд рдореЗрдореЛрд░реА рдмреНрд▓реЙрдХреЛрдВ рдХреЗ рдПрдХ рдкреВрд▓ рдХреЛ рд╕рдВрджрд░реНрднрд┐рдд рдХрд░рддреЗ рд╣реИрдВ (рджреЗрдЦреЗрдВ
src / memory.h )ред рдЬрдм рднреА рд╣рдореЗрдВ рдмреНрд▓реЙрдХ (рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, __mutex_bode) рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рддреЛ рдЗрд╕ рдкреВрд▓ рдХрд╛ рдирдордХ рдПрдХ рдзреАрдореА рдореЙрд▓реЛрдХ рдХреЛ рдХреЙрд▓ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рд╡реИрд╕реЗ, рдореЗрд░реЗ рдкрд╛рд╕ рдЕрднреА рднреА рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рдмрд┐рдирд╛ рдпрд╣ рдкреВрд▓ рд╣реИ (рдХреЗрд╡рд▓ рдПрдХ рд╕реНрдЯрдм рд╕реАрдзреЗ рдореЙрд▓реЛрдХ рдХрд╣ рд░рд╣рд╛ рд╣реИ), рд╕рд╛рде рд╣реА рд╕рд╛рде рдореЙрд▓реЙрдХ рднреАред рдЕрдЧрд░ рдХрд┐рд╕реА рдХреЛ рдкрд╣рд▓реА рдпрд╛ рджреВрд╕рд░реЗ рдкреЛрд░реНрдЯ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдПрдХ рдЕрдиреВрдард╛ рдЗрдЪреНрдЫрд╛ рд╣реИ - рд▓рд┐рдЦрдирд╛ред
4. рдпрджрд┐ рдЖрдк рдкрд╣рд▓реЗ рдкреНрд░рдпрд╛рд╕ рдХреЗ рдмрд╛рдж рд╕реЛ рд╕рдХрддреЗ рд╣реИрдВ, рддреЛ M рдХреЛ рдкрдХрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП N рдкреНрд░рдпрд╛рд╕ рдХреНрдпреЛрдВ рдХрд░реЗрдВ? рдЖрдк рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдпрд╣ рд╕рд┐рд░реНрдл рдмрд╣реБрдд рдкреНрд░рднрд╛рд╡реА рдирд╣реАрдВ рд╣реИред рдПрдХ рд╕реНрд╡рд┐рдЪрд▓реЙрдХ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдВрджрд░реНрдн рд╕реНрд╡рд┐рдЪрд┐рдВрдЧ рд╕рдордп рдПрдХ рдкреНрд░рдпрд╛рд╕ рд╕реЗ рдХрд╛рдлреА рдЕрдзрд┐рдХ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдпрд╣ рдПрди рдкреНрд░рдпрд╛рд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рддрд░реНрдХрд╕рдВрдЧрдд рд╣реИ (рдХреЛрдб 1000 рдореЗрдВ, рдЫрдд рд╕реЗ рд▓рд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рднрд╡рд┐рд╖реНрдп рдореЗрдВ рдпрд╣ рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдХрд┐ рд╡реНрдпрд╡рд╣рд╛рд░рд┐рдХ рдорд╛рдк рдХрд╛ рд╕рдВрдЪрд╛рд▓рди, рд╡реНрдпреБрддреНрдкрдиреНрди рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдПрдХ рдЕрдзрд┐рдХ рдЙрдЪрд┐рдд рдПрди рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдФрд░ рдФрдЪрд┐рддреНрдп рдХрд░рдирд╛)ред
5. рдХреЛрдб pause_thread рдХреЗ рд╕рдВрд╢реЛрдзрд┐рдд рд╕рдВрд╕реНрдХрд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ: pause_this_threadред рд╡рд░реНрддрдорд╛рди рдкреНрд░рд╡рд╛рд╣ рдХреЛ euthanizing рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдпрд╣ рдкрд░рдорд╛рдгреБ (рд░реБрдХрд╛рд╡рдЯ рдореЗрдВ) рдЗрд╕рдХреЗ рд▓рд┐рдП рдкреНрд░реЗрд╖рд┐рдд рд╕реНрдкрд┐рдирд▓реЙрдХ рдХреЛ рдЫреЛрдбрд╝рддрд╛ рд╣реИред
рдЬрдм рдореНрдпреВрдЯреЗрдХреНрд╕ рдХреЛ рдореБрдХреНрдд рдХрд░ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдореЗрдЬрдмрд╛рди рдЗрд▓реЙрдХ рдХреЛ рдкрдХрдбрд╝ рд▓реЗрддрд╛ рд╣реИ, рдФрд░ рдлрд┐рд░ рдХрддрд╛рд░ рдореЗрдВ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░ рд░рд╣реЗ рдереНрд░реЗрдбреНрд╕ рдХреА рдЬрд╛рдВрдЪ рдХрд░рддрд╛ рд╣реИред рдпрджрд┐ рдзрд╛рд░рд╛ рдорд┐рд▓рддреА рд╣реИ, рддреЛ рдпрд╣ рдЙрдарддрд╛ рд╣реИ, рдореНрдпреВрдЯреЗрдХреНрд╕ рдХрд╛ рдирдпрд╛ рдорд╛рд▓рд┐рдХ рдмрди рдЬрд╛рддрд╛ рд╣реИред рдпрджрд┐ рдХреЛрдИ рд▓рдВрдмрд┐рдд рдереНрд░реЗрдб рдирд╣реАрдВ рд╣реИрдВ, рддреЛ рд╣реЛрд╕реНрдЯ Mlock рдФрд░ рдирд┐рдХрд╛рд╕ рджреЗрддрд╛ рд╣реИред
static inline void release_mutex(struct mutex *mutex) { extern void __awake_in_mutex(struct mutex *mutex); acquire_spinlock(&mutex->ilock, 0); if (mutex->tail) __awake_in_mutex(mutex); else release_spinlock_int(&mutex->mlock); release_spinlock(&mutex->ilock); } INTERNAL void __awake_in_mutex(struct mutex *mutex) { struct __mutex_node *node; err_code err; do { node = mutex->tail; mutex->tail = node->next; if (mutex->head == node) mutex->head = NULL; err = resume_thread(node->id); free_block(&mutex_node_pool, node); } while (mutex->tail && err); if (!mutex->tail) release_spinlock_int(&mutex->mlock); }
рдореИрдВ рдиреАрдВрдж рд╕рдорд╛рд░реЛрд╣ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдмрд╛рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛, рд▓реЗрдХрд┐рди рдЗрд╕ рдкреЛрд╕реНрдЯ рдореЗрдВ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд╡рд┐рдЪрд╛рд░ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рднреЛрдЬрди рд╢рд╛рдорд┐рд▓ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдВ рдЗрд╕реЗ рдЕрдЧрд▓реА рдмрд╛рд░ рддрдХ рд╕реНрдердЧрд┐рдд рдХрд░ рджреВрдВрдЧрд╛ред
PS рдпрджрд┐ рдЖрдкрдХреЛ рдХреЛрдб рдореЗрдВ рддреНрд░реБрдЯрд┐рдпрд╛рдВ рдорд┐рд▓рддреА рд╣реИрдВ - рддреЛ рдЕрд╡рд╢реНрдп рд▓рд┐рдЦреЗрдВред