Читаем UNIX Network Programming. Volume 2 Second Edition. Interprocess Communications полностью

46  va_start(ap, fmt);

47  err_doit(0, LOG_INFO, fmt, ap);

48  va_end(ap);

49  return;

50 }


51 /* Фатальная ошибка не при системном вызове.

52  * Вывод сообщения и возврат. */

53 void

54 err_quit(const char *fmt, ...)

55 {

56  va_list ap;

57  va_start(ap, fmt);

58  err_doit(0, LOG_ERR, fmt, ap);

59  va_end(ap);

60  exit(1);

61 }


62 /* Вывод сообщения и возврат.

63  * Вызывающий указывает "errnoflag" и "level". */

64 static void

65 err_doit(int errnoflag, int level, const char *fmt, va_list ap)

66 {

67  int errno_save, n;

68  char buf[MAXLINE];

69  errno_save = errno; /* значение может понадобиться вызвавшему */

70 #ifdef HAVE_VSNPRINTF

71  vsnprintf(buf, sizeof(buf), fmt, ар); /* защищенный вариант */

72 #else

73  vsprintf(buf, fmt, ар); /* незащищенный вариант */

74 #endif

75  n = strlen(buf);

76  if (errnoflag)

77   snprintf(buf+n, sizeof(buf)-n, ": %s", strerror(errno_save));

78  strcat(buf, "\n");

79  if (daemon_proc) {

80   syslog(level, buf);

81  } else {

82   fflush(stdout); /* если stdout и stderr одинаковы */

83   fputs(buf, stderr);

84   fflush(stderr);

85  }

86  return;

87 }

ПРИЛОЖЕНИЕ Г

Решения некоторых упражнений

Глава 1

1. В обоих процессах нужно лишь указать флаг O_APPEND при вызове функции open или режим дополнения файла при вызове fopen. Ядро гарантирует, что данные будут дописываться в конец файла. Это самая простая форма синхронизации доступа к файлу. На с. 60-61 [21] об этом рассказывается более подробно. Синхронизация становится проблемой при обновлении имеющихся в файле данных, как это происходит в базах данных.

2. Обычно встречается что-нибудь вроде:

#ifdef REENTRANT

#define errno (*_errno)

#else

extern int errno;

#endif

Если определена константа _REENTRANT, обращение к errno приводит к вызову функции _errno, возвращающей адрес переменной errno вызвавшего потока. Эта переменная, скорее всего, хранится в области собственных данных этого потока (раздел 23.5 [24]). Если константа REENTRANT не определена, переменная errno является глобальной.

Глава 2

1. Эти два бита могут менять действующий идентификатор пользователя и/или группы выполняющейся программы. Идентификаторы используются в разделе 2.4.

2. Сначала следует указать флаги O_CREAT | O_EXCL, и если вызов окажется успешным, будет создан новый объект. Если вызов вернет ошибку EEXIST, объект уже существует и программа должна вызвать open еще раз, без флага O_CREAT или O_EXCL Второй вызов должен оказаться успешным, но есть вероятность, что он вернет ошибку ENOENT, если какой-либо другой поток или процесс удалит объект в промежутке между этими двумя вызовами.

Глава 3

1. Текст пpoгрaммы приведен в листинге Г.1.[1]

Листинг Г.1. Вывод идентификатора и порядкового номера слота

//svmsg/slotseq.c

1  #include "unpipc.h"


2  int

3  main(int argc, char **argv)

4  {

5   int i, msqid;

6   struct msqid_ds info;

7   for (i = 0; i 10; i++) {

8    msqid = Msgget(IPC_PRIVATE, SVMSG_MODE | IPC_CREAT);

9    Msgctl(msqid, IPC_STAT, info);

10   printf("msqid = %d, seq = %lu\n", msqid, info.msg_perm.seq);

11   Msgctl(msqid, IPC_RMID, NULL);

12  }

13  exit(0);

14 }

2. Первый вызов msgget задействует первую свободную очередь сообщений, порядковый номер которой имеет значение 20 после двукратного запуска программы из листинга 3.2, и вернет идентификатор 1000. Если предположить, что следующая доступная очередь сообщений никогда ранее не использовалась, ее порядковый номер будет иметь значение 0, а возвращаться будет идентификатор 1.

3. Программа приведена в листинге Г.2.

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже