38 */

39 status = pthread_mutex_unlock (&mutex);

40 if (status != 0)

41  err_abort (status, 'Unlock in parent handler');

42 }

43

44 /*

45 * This routine will be called after executing the fork, within

46 * the child process.

47 */

48 void fork_child (void)

49 {

50 int status; 51

52 /*

53 * Update the file scope 'self_pid' within the child process, and

54 * unlock the mutex.

55 */

56 self_pid = getpid ();

57 status = pthread_mutex_unlock (&mutex);

58 if (status != 0)

59 err_abort (status, 'Unlock in child handler');

60 }

61

62 /*

63 * Thread start routine, which will fork a new child process.

64 */

65 void *thread_routine (void *arg)

66 {

67 pid_t child_pid;

68 int status;

69

70 child_pid = fork ( );

71 if (child_pid == (pid_t)-l)

72 errno_abort ('Fork');

73

74 /*

75 * Lock the mutex — without the atfork handlers, the mutex will

76 * remain locked in the child process and this lock attempt will

77 * hang (or fail with EDEADLK) in the child.

78 */

79 status = pthread_mutex_lock (&mutex);

80 if (status != 0)

81  err_abort (status, 'Lock in child');

82 status = pthread_mutex_unlock (&mutex);

83 if (status != 0)

84  err_abort (status, 'Unlock in child');

85 printf ('After fork: %d (%d) ', child_pid, self_pid);

86 if (child_pid != 0) {

87 if ((pid_t)-l == waitpid (child_pid, (int*)0, 0))

88 errno_abort ('Wait for child');

89 }

90 return NULL;

91 }

92

93 int main (int argc, char *argv[])

94 {

95 pthread_t fork_thread;

96 int atfork_flag = 1;

97 int status;

98

99 if (argc > 1)

100 atfork_flag = atoi (argv[l]);

101 if (atfork_flag) {

102 status = pthread_atfork (

103 fork_prepare, fork_parent, fork_child);

104 if (status != 0)

105 err_abort (status, 'Register fork handlers');

106 }

107 self_pid = getpid ();

108 status = pthread_mutex_lock (&mutex);

109 if (status != 0)

110 err_abort (status, 'Lock mutex');

111 /*

112 * Create a thread while the mutex is locked. It will fork a

113 * process, which (without atfork handlers) will run with the

114 * mutex locked.

115 */

116 status = pthread_create (

117 &fork_thread, NULL, thread_routine, NULL);

118 if (status != 0)

119 err_abort (status, 'Create thread');

120 sleep (5);

121 status = pthread_mutex_unlock (&mutex);

122 if (status != 0)

123 err_abort (status, 'Unlock mutex');

124 status = pthread_join (fork_thread, NULL);

125 if (status != 0)

126 err_abort (status, 'Join thread');

127 return 0;

128 }

¦ atfork.c

Now, imagine you are writing a library that manages network server connections, and you create a thread for each network connection that listens for service requests. In your prepare fork handler you lock all of the library's mutexes to make sure the child's state is consistent and recoverable. In your parent fork handler you unlock those mutexes and return. When designing the child fork handler, you need to decide exactly what a fork means to your library. If you want to retain all network connections in the child, then you would create a new listener thread for each connection and record their identifiers in the appropriate data structures before releasing the mutexes. If you want the child to begin with no open connections, then you would locate the existing parent connection data structures and free them, closing the associated files

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату