Кожен процес має власну чергу повідомлень (Message Queue), через яку здійснюється міжпроцесний обмін повідомленнями. Ця функціональність використовується не лише для передачі повідомлень прикладних програм між процесами, а й для системних сповіщень ядра (наприклад, повідомлень про завершення дочірніх процесів та сповіщень таймера). З цієї причини формати окремих типів повідомлень регламентуються системою.
Повідомлення надсилається у чергу повідомлень цільового процесу, а адресат вказується за допомогою його ідентифікатора процесу PID. Також процес-відправник однозначно ідентифікується за власним PID.
Кожне повідомлення має наведену нижче структуру і поділяється на 31 тип за полем msg_type (значення 1–31). Завдяки побітовій масці типів (Type Mask) під час прийому або очищення повідомлень можна вибірково вказувати один або кілька типів повідомлень одночасно.
typedef union {
struct {
W pid;
W code;
} ABORT; /* Повідомлення про аварійне завершення процесу (MS_ABORT) */
struct {
W pid;
W code;
} EXIT; /* Повідомлення про нормальне завершення процесу (MS_EXIT) */
struct {
W pid;
W code;
} TERM; /* Повідомлення про примусове завершення процесу (MS_TERM) */
struct {
W code;
} TMOUT; /* Повідомлення про спливання таймауту (MS_TMOUT) */
struct {
W code;
} SYSEVT; /* Повідомлення про системні події (MS_SYS1..MS_SYS31) */
struct {
UB msg_str[32];
} ANYMSG; /* Загальні повідомлення додатків (MS_USER) */
} MSGBODY;
typedef struct message {
W msg_type; /* Тип повідомлення (1..31) */
W msg_size; /* Розмір тіла повідомлення (байти) */
MSGBODY msg_body; /* Буфер тіла повідомлення */
} MESSAGE;
У чергу повідомлень процесу можуть надходити як повідомлення від інших процесів, так і повідомлення від власного процесу (якщо цільовим адресатом вказано власний процес), а також системні повідомлення про спливання таймауту (MS_TMOUT). Крім того, повідомлення про завершення дочірніх процесів (MS_ABORT, MS_EXIT, MS_TERM) також надходять у цю чергу.
Черга повідомлень працює за принципом FIFO — повідомлення записуються суворо у порядку надсилання. Якщо під час відправлення черга отримувача заповнена, відправник може заблокуватися до появи вільного місця або негайно повернути код помилки.
Зазвичай прийняті повідомлення накопичуються у черзі і вилучаються за запитом прийому повідомлення, проте за допомогою реєстрації обробника повідомлень (Message Handler) при надходженні повідомлення вказаного типу можна виконувати асинхронну обробку. Це застосовується як системне переривання.
Повідомлення поділяються на 31 тип за їхніми номерами 1–31: з них типи 1–5 зарезервовані ядром системного призначення, типи 6–23 зарезервовані підсистемами ядра та графічною оболонкою (Shell Manager), а типи 24–31 надаються для вільного використання прикладними програмами.
Типи повідомлень визначаються наступним чином:
#define MS_ABORT ( 1) /* Аварійне завершення процесу */ #define MS_EXIT ( 2) /* Нормальне завершення процесу */ #define MS_TERM ( 3) /* Примусове завершення процесу */ #define MS_TMOUT ( 4) /* Спливання таймауту */ #define MS_SYSEVT ( 5) /* Критична системна подія */ #define MS_SYS1 ( 6) /* Системне резервування ядра */ #define MS_SYS2 ( 7) /* Системне резервування ядра */ #define MS_SYS3 ( 8) /* Системне резервування ядра */ #define MS_SYS4 ( 9) /* Системне резервування ядра */ #define MS_SYS5 (10) /* Системне резервування ядра */ #define MS_MNG0 (11) /* Резервування оболонки Shell */ #define MS_MNG1 (12) /* Резервування оболонки Shell */ #define MS_MNG2 (13) /* Резервування оболонки Shell */ #define MS_MNG3 (14) /* Резервування оболонки Shell */ #define MS_MNG4 (15) /* Резервування оболонки Shell */ #define MS_MNG5 (16) /* Резервування оболонки Shell */ #define MS_MNG6 (17) /* Резервування оболонки Shell */ #define MS_MNG7 (18) /* Резервування оболонки Shell */ #define MS_MNG8 (19) /* Резервування оболонки Shell */ #define MS_MNG9 (20) /* Резервування оболонки Shell */ #define MS_MNG10 (21) /* Резервування оболонки Shell */ #define MS_MNG11 (22) /* Резервування оболонки Shell */ #define MS_MNG12 (23) /* Резервування оболонки Shell */ #define MS_TYPE0 (24) /* Повідомлення прикладних додатків */ #define MS_TYPE1 (25) #define MS_TYPE2 (26) #define MS_TYPE3 (27) #define MS_TYPE4 (28) #define MS_TYPE5 (29) #define MS_TYPE6 (30) #define MS_TYPE7 (31) #define MS_MIN ( 1) /* Мінімальний номер типу повідомлення */ #define MS_MAX (31) /* Максимальний номер типу повідомлення */
Кожному типу повідомлення відповідає бітовий прапор у масці типів (Type Mask), і завдяки побітовій комбінації (OR) масок можна вказувати кілька типів повідомлень одночасно.
Маски типів повідомлень визначаються наступним чином:
#define MSGMASK(msgtype) (1 << ((msgtype) - 1)) #define MM_ABORT MSGMASK(MS_ABORT) /* Аварійне завершення процесу */ #define MM_EXIT MSGMASK(MS_EXIT) /* Нормальне завершення процесу */ #define MM_TERM MSGMASK(MS_TERM) /* Примусове завершення процесу */ #define MM_TMOUT MSGMASK(MS_TMOUT) /* Спливання таймауту */ #define MM_SYSEVT MSGMASK(MS_SYSEVT) /* Критична системна подія */ #define MM_SYS1 MSGMASK(MS_SYS1) /* Системне резервування ядра */ #define MM_SYS2 MSGMASK(MS_SYS2) /* Системне резервування ядра */ #define MM_SYS3 MSGMASK(MS_SYS3) /* Системне резервування ядра */ #define MM_SYS4 MSGMASK(MS_SYS4) /* Системне резервування ядра */ #define MM_SYS5 MSGMASK(MS_SYS5) /* Системне резервування ядра */ #define MM_MNG0 MSGMASK(MS_MNG0) /* Резервування оболонки Shell */ #define MM_MNG1 MSGMASK(MS_MNG1) /* Резервування оболонки Shell */ #define MM_MNG2 MSGMASK(MS_MNG2) /* Резервування оболонки Shell */ #define MM_MNG3 MSGMASK(MS_MNG3) /* Резервування оболонки Shell */ #define MM_MNG4 MSGMASK(MS_MNG4) /* Резервування оболонки Shell */ #define MM_MNG5 MSGMASK(MS_MNG5) /* Резервування оболонки Shell */ #define MM_MNG6 MSGMASK(MS_MNG6) /* Резервування оболонки Shell */ #define MM_MNG7 MSGMASK(MS_MNG7) /* Резервування оболонки Shell */ #define MM_MNG8 MSGMASK(MS_MNG8) /* Резервування оболонки Shell */ #define MM_MNG9 MSGMASK(MS_MNG9) /* Резервування оболонки Shell */ #define MM_MNG10 MSGMASK(MS_MNG10) /* Резервування оболонки Shell */ #define MM_MNG11 MSGMASK(MS_MNG11) /* Резервування оболонки Shell */ #define MM_MNG12 MSGMASK(MS_MNG12) /* Резервування оболонки Shell */ #define MM_TYPE0 MSGMASK(MS_TYPE0) /* Повідомлення прикладних додатків */ #define MM_TYPE1 MSGMASK(MS_TYPE1) #define MM_TYPE2 MSGMASK(MS_TYPE2) #define MM_TYPE3 MSGMASK(MS_TYPE3) #define MM_TYPE4 MSGMASK(MS_TYPE4) #define MM_TYPE5 MSGMASK(MS_TYPE5) #define MM_TYPE6 MSGMASK(MS_TYPE6) #define MM_TYPE7 MSGMASK(MS_TYPE7) #define MM_ALL (0x7fffffff) /* Маска всіх типів повідомлень */ #define MM_NULL (0) /* Порожня маска */
Системні повідомлення автоматично генеруються ядром операційної системи і мають наведений нижче вміст. Вони не відкидаються при переповненні черги і завжди гарантовано доставляються.
MS_ABORT — Повідомлення про аварійне завершення процесу:
Надсилається батьківському процесу від дочірнього процесу, якщо дочірній процес був аварійно завершений внаслідок системної помилки або спрацювання обробника MH_TERM.
W msg_type /* Тип = MS_ABORT (1) */ W msg_size /* Розмір тіла у байтах (8) */ W pid /* PID завершеного дочірнього процесу */ W code /* Код системної помилки (або 0 при зупинці MH_TERM) */
MS_EXIT — Повідомлення про нормальне завершення процесу:
Надсилається батьківському процесу, коли дочірній процес завершує виконання викликом ext_prc().
W msg_type /* Тип = MS_EXIT (2) */ W msg_size /* Розмір тіла у байтах (8) */ W pid /* PID завершеного дочірнього процесу */ W code /* Код завершення, переданий у ext_prc() */
MS_TERM — Повідомлення про примусове завершення процесу:
Надсилається батьківському процесу, коли дочірній процес примусово припиняє виконання викликом ter_prc().
W msg_type /* Тип = MS_TERM (3) */ W msg_size /* Розмір тіла у байтах (8) */ W pid /* PID припиненого дочірнього процесу */ W code /* Код завершення, переданий у ter_prc() */
MS_TMOUT — Повідомлення про спливання таймауту:
Надсилається власному процесу після закінчення часу, вказаного у виклику таймера req_tmg().
W msg_type /* Тип = MS_TMOUT (4) */ W msg_size /* Розмір тіла у байтах (4) */ W code /* Код користувача, переданий у req_tmg() */
За замовчуванням повідомлення у черзі очікують на явний виклик прийому rcv_msg(). Проте за допомогою реєстраційної функції def_msg() процес може визначити функцію обробника повідомлень (Message Handler) для кожного з типів повідомлень (1–31).
Правила виконання та обробки повідомлень:
При надходженні повідомлення, для якого зареєстровано обробник, звичайна послідовність виконання процесу переривається, повідомлення вилучається з черги, а управління передається у функцію обробника.
Обробник виконується у контексті головної задачі процесу. Якщо під час виконання обробника надходить ще одне повідомлення із зареєстрованим обробником, його обробка затримується у черзі до завершення поточного обробника викликом ret_msg().
Якщо процес перебував у стані блокування (наприклад, очікував системного виклику або події), обробник виконується негайно, а після його завершення заблокований виклик повертає код помилки ER_MINTR (якщо обробник не використовує ret_msg(0)).
Для виходу з обробника слід викликати ret_msg(). Виклик ret_msg(0) повертає процес у точку переривання. Виклик ret_msg(1) дозволяє виконати нелокальний перехід за допомогою longjmp() на попередньо збережений контекст (setjmp).
Прототип функції обробника повідомлень:
VOID msg_hdr(W pid, MESSAGE *r_msg)
{
/* pid — PID процесу-відправника (0 якщо відправник — власний процес) */
/* r_msg — вказівник на прийняте повідомлення */
/* [Обробка прийнятого повідомлення] */
ret_msg(0); /* Завершення обробника (повернення у точку переривання) */
/* АБО */
ret_msg(1); /* Підготовка до нелокального переходу */
longjmp(reent, code); /* Перехід longjmp на збережений середовищний контекст */
}
Система надає 3 стандартні системні обробники за замовчуванням:
MH_NONE — Ігнорування повідомлення:
Повідомлення вилучається з черги та ігнорується без виконання будь-яких дій. Заблоковані системні виклики очікування НЕ перериваються.
MH_BREAK — Переривання очікування:
Повідомлення вилучається з черги. Наявні заблоковані виклики очікування перериваються і повертають код помилки ER_MINTR.
MH_TERM — Аварійне завершення процесу:
При надходженні повідомлення процес негайно припиняє виконання і надсилає батьківському процесу системне повідомлення MS_ABORT з кодом 0.
typedef union {
struct { /* MS_ABORT */
W pid;
W code;
} ABORT;
struct { /* MS_EXIT */
W pid;
W code;
} EXIT;
struct { /* MS_TERM */
W pid;
W code;
} TERM;
struct { /* MS_TMOUT */
W code;
} TMOUT;
struct { /* MS_SYSEVT */
W code;
} SYSEVT;
struct { /* Загальні повідомлення додатків (MS_USER) */
UB msg_str[32];
} ANYMSG;
} MSGBODY;
typedef struct message {
W msg_type; /* Тип повідомлення (1..31) */
W msg_size; /* Розмір тіла повідомлення (у байтах) */
MSGBODY msg_body; /* Буфер тіла повідомлення */
} MESSAGE;
#define MSGSIZE(msgsz) (offsetof(MESSAGE, msg_body) + msgsz)
#define WAIT 0x0000 /* Очікування у разі заповнення/відсутності повідомлення */ #define NOWAIT 0x0001 /* Негайне повернення без очікування */ #define CONFM 0x0002 /* Запит підтвердження прийому від отримувача */ #define WAIEVT 0x0004 /* Очікування повідомлення або сигналу brk_msg() */ #define CLR 0x0000 /* Вилучення повідомлення з черги після прийому */ #define NOCLR 0x0008 /* Читання повідомлення без вилучення з черги */ #define CHECK 0x0010 /* Перевірка наявності повідомлення без копіювання */
#define MH_NONE ((FUNCP)1) /* Ігнорування повідомлень */ #define MH_BREAK ((FUNCP)2) /* Переривання очікування (ER_MINTR) */ #define MH_TERM ((FUNCP)3) /* Аварійне завершення процесу */
|
ERR snd_msg(W pid, MESSAGE* msg, W opt)
W pid PID цільового процесу-отримувача
> 0 : Конкретний цільовий процес
= 0 : Власний процес
=-1 : Усі дочірні процеси
MESSAGE* msg Вказівник на структуру надсиланого повідомлення
W opt Режими надсилання (NOWAIT | WAIT | CONFM)
NOWAIT:
Якщо черга отримувача заповнена, виклик негайно повертає код помилки ER_NOSPC без очікування.
WAIT:
Якщо черга отримувача заповнена, процес-відправник переходить у стан очікування до появи вільного місця у черзі.
CONFM:
Запитує підтвердження прийому. Відправник блокується доти, доки отримувач не прочитає повідомлення викликом rcv_msg() у режимі CLR.
= 0 Успішне виконання (E_OK) < 0 Помилка (Код помилки)
Надсилає повідомлення msg у чергу повідомлень процесу pid.
ER_ADR : Неприпустима адреса вказівника (msg) у віртуальній пам'яті. ER_MINTR : Обробку перервано внаслідок надходження системного сигналу. ER_NOPRC : Процес із вказаним PID не існує або вже завершений. ER_NOSPC : Черга повідомлень отримувача заповнена (при режимі NOWAIT). ER_PAR : Неприпустиме значення одного з параметрів системного виклику. ER_SELF : Спроба надіслати повідомлення самому собі у режимі підтвердження CONFM. ER_SZOVR : Розмір тіла повідомлення виходить за дозволені межі.
|
WERR rcv_msg(W t_mask, MESSAGE* msg, W msgsz, W opt)
W t_mask Маска типів повідомлень для прийому (наприклад, MM_ALL) MESSAGE* msg Буфер для збереження прийнятого повідомлення W msgsz Розмір буфера msg у байтах (msgsz >= 8) W opt Режими прийому: (WAIT | NOWAIT | WAIEVT) | (CLR | NOCLR) | (CHECK)
WAIT:
Якщо відповідне повідомлення відсутнє у черзі, процес очікує його надходження.
NOWAIT:
Якщо відповідне повідомлення відсутнє у черзі, виклик негайно повертає код помилки ER_NONE.
WAIEVT:
Чекає на повідомлення або сигнал переривання, згенерований системним викликом brk_msg().
CLR:
Після прочитання повідомлення воно вилучається з черги повідомлень (режим за замовчуванням).
NOCLR:
Повідомлення копіюється у буфер msg, але залишається у черзі повідомлень.
CHECK:
Перевіряє наявність повідомлення у черзі без копіювання його вмісту у буфер.
> 0 Успішне виконання (PID процесу-відправника) = 0 Успішне виконання (відправник відсутній або перевірка CHECK) < 0 Помилка (Код помилки)
Зчитує із черги повідомлення, тип якого відповідає масці t_mask, і копіює його у буфер msg.
ER_ADR : Неприпустима адреса вказівника (msg) у віртуальній пам'яті. ER_MINTR : Обробку перервано внаслідок надходження системного сигналу. ER_NONE : Повідомлення з вказаною маскою t_mask відсутнє у черзі (при NOWAIT). ER_PAR : Неприпустиме значення одного з параметрів (наприклад, msgsz < 8). ER_SZOVR : Наданий буфер msgsz занадто малий для збереження тіла даного повідомлення.
|
ERR clr_msg(W t_mask, W last_mask)
W t_mask Маска типів повідомлень для вилучення з черги (наприклад, MM_ALL) W last_mask Маска типів повідомлень для вилучення тільки останніх записів
>= 0 Успішне виконання (Кількість вилучених повідомлень) < 0 Помилка (Код помилки)
Вилучає з черги повідомлення власного процесу, тип яких збігається з маскою t_mask.
ER_PAR : Неприпустиме значення параметрів маски (t_mask <= 0).
|
ERR req_tmg(W time, W code)
W time Час затримки у мілісекундах (time > 0) W code Користувацький код, що буде переданий у повідомленні MS_TMOUT
= 0 Успішне виконання (E_OK) < 0 Помилка (Код помилки)
Замовляє надсилання системного повідомлення про спливання таймауту (MS_TMOUT) із кодом code у чергу власного процесу через time мілісекунд.
ER_NOSPC : Недостатньо системної пам'яті для реєстрації таймера. ER_PAR : Неприпустиме значення інтервалу часу (time <= 0).
|
ERR can_tmg(VOID)
Відсутні (VOID)
= 0 Успішне виконання (E_OK)
Скасовує раніше встановлений таймер повідомлень req_tmg() для власного процесу.
Помилок немає (завжди повертає E_OK).
|
ERR def_msg(W t_mask, FP msghdr)
W t_mask Маска типів повідомлень, для яких призначається обробник
FP msghdr Вказівник на функцію обробника або системна константа:
= MH_NONE : Ігнорування повідомлень
= MH_BREAK : Переривання очікування (ER_MINTR)
= MH_TERM : Аварійне завершення процесу
= NULL : Скидання на стандартний обробник (MH_NONE)
= 0 Успішне виконання (E_OK) < 0 Помилка (Код помилки)
Реєструє функцію обробника msghdr для повідомлень, маска типів яких збігається з t_mask.
ER_ADR : Неприпустима адреса вказівника функції msghdr у пам'яті. ER_PAR : Неприпустиме значення маски (t_mask <= 0).
|
ERR ret_msg(W ret)
W ret Режим повернення:
= 0 : Повернення у точку переривання основної програми
!= 0 : Підготовка до нелокального переходу longjmp()
Не повертає управління (при ret = 0) = 0 Успішне виконання (при ret != 0 перед викликом longjmp)
Системний виклик для виходу з функції обробника повідомлень. Повідомляє ядро про завершення асинхронної обробки і відновлює стан процесу.
Помилок немає.
|
ERR brk_msg(VOID)
Відсутні (VOID)
= 0 Успішне виконання (E_OK)
Примусово перериває стан очікування для задачі власного процесу, заблокованої системним викликом rcv_msg() у режимі WAIEVT.
Помилок немає (завжди повертає E_OK).