posix_spawn 계열 함수


int posix_spawn(pid_t *restrict pid, const char *restrict path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *restrict attrp, char *const argv[restrict], char *const envp[restrict]);

int posix_spawnp(pid_t *restrict pid, const char *restrict file, cosnt posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *restrict attrp, char *const argv[restrict], char *const envp[restrict]);
  • 앞서 언급했듯이 fork-exec는 부모 프로세스의 자원을 선택적으로 복제할 수 없으므로, 성능상의 문제와 추가적인 코딩이 복잡해지는 문제가 있었다.

  • 따라서, posix_spawn 계열에서는 부모 프로세스의 자원을 선택적으로 복제하거나, 다룰 수 있는 통합 인터페이스가 제안되었는데 이를 가능하게 하는 것이 바로 file_actions, attrp 인수이다.

  • 만약 file_actions, attrp 인수 부분에 NULL을 지정하면, fork-exec와 동일한 작동, 즉 부모 프로세스의 자원을 모두 복제한다.

  • posix_spawn도 기본적으로는 부모 프로세스가 열었던 파일은 모두 상속 받는다. 만약 추가로 열어야하는 파일이 있거나, 기존에 열은 파일을 닫아야 할 필요가 있는 경우에는 file_actions 매개변수를 이용한다.

posix_spawn_file_actions_t 구조체 조작


int posix_spawn_file_actions_init(posix_spawn_file_actions_t *file_actions);
int posix_spawn_file_destroy(posix_spawn_file_actions_t *file_actions);
int posix_spawn_file_actions_addopen(posix_spawn_file_actions_t *restrict file_actions, int fildes, const char *restrict path, int oflag, mode_t mode);
int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *file_actions, int fildes);
int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *file_actions, int fildes, int newfildes);
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <spawn.h>
#include <fcntl.h>
#include <string.h>

int main() {
	int ret_err = 0;
	pid_t pid_child;
	char buf_err[64];
	posix_spawn_file_actions_t posix_faction; /* file action struct */
	char *argv_child[] = { "forkexec_child", NULL };
	printf("Parent[%d]: Start\n", getpid());

	if((ret_err = posix_spawn_file_actions_init(&posix_faction)) != 0) { /* init */
		strerror_r(ret_err, buf_err, sizeof(buf_err));
		fprintf(stderr, "Fail: file_actions_init :%s\n", buf_err);
		exit(EXIT_FAILURE);
	}
	if ((ret_err = posix_spawn_file_actions_addopen(&posix_faction, 3,
					"pspawn.log", O_WRONLY | O_CREAT | O_APPEND, 0664 )) != 0) {
		strerror_r(ret_err, buf_err, sizeof(buf_err));
		fprintf(stderr, "Fail: file_actions_addopen: %s\n", buf_err);
		exit(EXIT_FAILURE);
	}
	ret_err = posix_spawn(&pid_child,
			argv_child[0],
			&posix_faction,
			NULL,
			argv_child,
			NULL);

	if ((ret_err = posix_spawn_file_actions_destroy(&posix_faction)) != 0) {
		strerror_r(ret_err, buf_err, sizeof(buf_err));
		fprintf(stderr, "Fail: file_actions_destory: %s\n", buf_err);
		exit(EXIT_FAILURE);
	}
	printf("Parent[%d]: Wait for child(%d)\n", getpid(), (int)pid_child);
	(void)wait(NULL);
	printf("Parent[%d]: Exit\n", getpid());
	return 0;
}
  • 메모리를 해제하는 부분을 유의해서 보자, 예제에서는 한번 실행되고 곧바로 종료되기 때문에, 해제하지 않아도 메모리 누수를 신경 쓸 필요가 없지만, 연속적으로 실행되는 실무 프로그램에서는 민감한 문제이므로, 꼭 메모리 해제에 신경을 써야 한다.

posix_spawnattr_t 구조체 조작


int posix_spawnattr_init(posix_spawnattr_t *attr);
int posix_spawnattr_destroy(posix_spawnattr_t *attr);

int posix_spawnattr_getflags(const posix_spawnattr_t *restrict attr, short *restrict flags);
int posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags);
  • posix_spawnattr_t 구조체는 posix_spawnattr_init()로 초기화를 한 뒤에 사용해야만 한다.

  • 그리고 사용이 끝난 구조체는 posix_spawnattr_destroy()로 메모리를 해제해야 누수가 발생하지 않는다.

  • 따라서 메모리를 해제한 후에, 다시 사용할 필요가 있다면, 다시 posix_spawnattr_init() 로 초기화를 한 후에 사용하도록 한다.

  • posix_spawnattr_t에는 EUID, 프로세스 그룹, 기본 시그널 작동, 시그널 블록 마스크, 스케줄링 파라미터, 스케줄러를 설정할 수 있다.

  • 이중에서 EUID 설정을 제외한 나머지 기능들은 해당 속성의 on/off를 의미하는 플래그를 설정하고 개별적으로 속성을 등록하는 함수를 사용해야한다.

참고 문헌

>> Home