All of lore.kernel.org
 help / color / mirror / Atom feed
* clone3() example code
@ 2019-10-25  8:13 Michael Kerrisk (man-pages)
  2019-10-25  8:41 ` Christian Brauner
  0 siblings, 1 reply; 4+ messages in thread
From: Michael Kerrisk (man-pages) @ 2019-10-25  8:13 UTC (permalink / raw)
  To: Christian Brauner; +Cc: Linux API, lkml

Hello Christian,

Do you have some example user-space code somewhere that illustrates
calling clone3(). I'm looking at how we might document that system
call in the manual page, and some example code to play with would be
useful at this point. (I already have a simple working test program,
but probably you have something better.)

Thanks,

Michael

-- 
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
Linux/UNIX System Programming Training: http://man7.org/training/

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: clone3() example code
  2019-10-25  8:13 clone3() example code Michael Kerrisk (man-pages)
@ 2019-10-25  8:41 ` Christian Brauner
  2019-10-25  9:49   ` Aleksa Sarai
  0 siblings, 1 reply; 4+ messages in thread
From: Christian Brauner @ 2019-10-25  8:41 UTC (permalink / raw)
  To: Michael Kerrisk (man-pages); +Cc: Christian Brauner, Linux API, lkml


On Fri, Oct 25, 2019 at 10:13:23AM +0200, Michael Kerrisk (man-pages) wrote:
> Hello Christian,

Hey Michael,

> 
> Do you have some example user-space code somewhere that illustrates
> calling clone3(). I'm looking at how we might document that system
> call in the manual page, and some example code to play with would be

Excellent!

> useful at this point. (I already have a simple working test program,
> but probably you have something better.)

Not sure about something better but one simple thing I used (a more
extensive test-suite is coming):

#define _GNU_SOURCE
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <sched.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mount.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/sysmacros.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <unistd.h>

#ifndef CLONE_PIDFD
#define CLONE_PIDFD 0x00001000
#endif

#ifndef __NR_clone3
#define __NR_clone3 -1
#endif

static pid_t sys_clone3(struct clone_args *args)
{
	return syscall(__NR_clone3, args, sizeof(struct clone_args));
}

static int wait_for_pid(pid_t pid)
{
	int status, ret;

again:
	ret = waitpid(pid, &status, 0);
	if (ret == -1) {
		if (errno == EINTR)
			goto again;

		return -1;
	}

	if (ret != pid)
		goto again;

	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
		return -1;

	return 0;
}

#define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr)))

int main(int argc, char *argv[])
{
	int pidfd = -1;
	pid_t parent_tid = -1, pid = -1;
	struct clone_args args = {0};

	args.parent_tid = ptr_to_u64(&parent_tid); /* CLONE_PARENT_SETTID */
	args.pidfd = ptr_to_u64(&pidfd); /* CLONE_PIDFD */
	args.flags = CLONE_PIDFD | CLONE_PARENT_SETTID;
	args.exit_signal = SIGCHLD;

	pid = sys_clone3(&args);
	if (pid < 0) {
		fprintf(stderr, "%s - Failed to create new process\n", strerror(errno));
		exit(EXIT_FAILURE);
	}

	if (pid == 0) {
		printf("Child process with pid %d\n", getpid());
		exit(EXIT_SUCCESS);
	}

	printf("Parent process received child's pid %d as return value\n", pid);
	printf("Parent process received child's pidfd %d\n", *(int *)args.pidfd);
	printf("Parent process received child's pid %d as return argument\n",
	       *(pid_t *)args.parent_tid);

	if (0) {
		if (waitid(P_ALL, pid, NULL, 0) == 0) {
			fprintf(stderr, "Managed to wait on CLONE_NO_WAITALL process with waitid(P_ALL)\n");
			exit(EXIT_FAILURE);
		}
		printf("Child process %d requested CLONE_NO_WAITALL\n", pid);
	} else {
		printf("Child process %d did not request CLONE_NO_WAITALL\n", pid);
	}

	if (wait_for_pid(pid))
		exit(EXIT_FAILURE);

	if (pid != *(pid_t *)args.parent_tid)
		exit(EXIT_FAILURE);

	close(pidfd);

	return 0;
}

Thanks!
Christian

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: clone3() example code
  2019-10-25  8:41 ` Christian Brauner
@ 2019-10-25  9:49   ` Aleksa Sarai
  2019-10-25  9:56     ` Christian Brauner
  0 siblings, 1 reply; 4+ messages in thread
From: Aleksa Sarai @ 2019-10-25  9:49 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Michael Kerrisk (man-pages), Christian Brauner, Linux API, lkml

[-- Attachment #1: Type: text/plain, Size: 2197 bytes --]

On 2019-10-25, Christian Brauner <christian.brauner@ubuntu.com> wrote:
> #define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr)))
> 
> int main(int argc, char *argv[])
> {
> 	int pidfd = -1;
> 	pid_t parent_tid = -1, pid = -1;
> 	struct clone_args args = {0};
> 
> 	args.parent_tid = ptr_to_u64(&parent_tid); /* CLONE_PARENT_SETTID */
> 	args.pidfd = ptr_to_u64(&pidfd); /* CLONE_PIDFD */
> 	args.flags = CLONE_PIDFD | CLONE_PARENT_SETTID;
> 	args.exit_signal = SIGCHLD;
> 
> 	pid = sys_clone3(&args);

I'd suggest that

	struct clone_args args = {
		.flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
		.parent_tid = ptr_to_u64(&parent_tid), /* CLONE_PARENT_SETTID */
		.pidfd = ptr_to_u64(&pidfd),           /* CLONE_PIDFD */
		.exit_signal = SIGCHLD,
	};

or alternatively

	pid = sys_clone3(&(struct clone_args) {
		.flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
		.parent_tid = ptr_to_u64(&parent_tid), /* CLONE_PARENT_SETTID */
		.pidfd = ptr_to_u64(&pidfd),           /* CLONE_PIDFD */
		.exit_signal = SIGCHLD,
	});

are easier to read.

> 	if (pid < 0) {
> 		fprintf(stderr, "%s - Failed to create new process\n", strerror(errno));
> 		exit(EXIT_FAILURE);
> 	}
> 
> 	if (pid == 0) {
> 		printf("Child process with pid %d\n", getpid());
> 		exit(EXIT_SUCCESS);
> 	}
> 
> 	printf("Parent process received child's pid %d as return value\n", pid);
> 	printf("Parent process received child's pidfd %d\n", *(int *)args.pidfd);
> 	printf("Parent process received child's pid %d as return argument\n",
> 	       *(pid_t *)args.parent_tid);
> 
> 	if (0) {
> 		if (waitid(P_ALL, pid, NULL, 0) == 0) {
> 			fprintf(stderr, "Managed to wait on CLONE_NO_WAITALL process with waitid(P_ALL)\n");
> 			exit(EXIT_FAILURE);
> 		}
> 		printf("Child process %d requested CLONE_NO_WAITALL\n", pid);
> 	} else {
> 		printf("Child process %d did not request CLONE_NO_WAITALL\n", pid);
> 	}
> 
> 	if (wait_for_pid(pid))
> 		exit(EXIT_FAILURE);
> 
> 	if (pid != *(pid_t *)args.parent_tid)
> 		exit(EXIT_FAILURE);
> 
> 	close(pidfd);
> 
> 	return 0;
> }

-- 
Aleksa Sarai
Senior Software Engineer (Containers)
SUSE Linux GmbH
<https://www.cyphar.com/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: clone3() example code
  2019-10-25  9:49   ` Aleksa Sarai
@ 2019-10-25  9:56     ` Christian Brauner
  0 siblings, 0 replies; 4+ messages in thread
From: Christian Brauner @ 2019-10-25  9:56 UTC (permalink / raw)
  To: Aleksa Sarai
  Cc: Michael Kerrisk (man-pages), Christian Brauner, Linux API, lkml

On Fri, Oct 25, 2019 at 08:49:56PM +1100, Aleksa Sarai wrote:
> On 2019-10-25, Christian Brauner <christian.brauner@ubuntu.com> wrote:
> > #define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr)))
> > 
> > int main(int argc, char *argv[])
> > {
> > 	int pidfd = -1;
> > 	pid_t parent_tid = -1, pid = -1;
> > 	struct clone_args args = {0};
> > 
> > 	args.parent_tid = ptr_to_u64(&parent_tid); /* CLONE_PARENT_SETTID */
> > 	args.pidfd = ptr_to_u64(&pidfd); /* CLONE_PIDFD */
> > 	args.flags = CLONE_PIDFD | CLONE_PARENT_SETTID;
> > 	args.exit_signal = SIGCHLD;
> > 
> > 	pid = sys_clone3(&args);
> 
> I'd suggest that
> 
> 	struct clone_args args = {
> 		.flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
> 		.parent_tid = ptr_to_u64(&parent_tid), /* CLONE_PARENT_SETTID */
> 		.pidfd = ptr_to_u64(&pidfd),           /* CLONE_PIDFD */
> 		.exit_signal = SIGCHLD,
> 	};
> 
> or alternatively
> 
> 	pid = sys_clone3(&(struct clone_args) {
> 		.flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
> 		.parent_tid = ptr_to_u64(&parent_tid), /* CLONE_PARENT_SETTID */
> 		.pidfd = ptr_to_u64(&pidfd),           /* CLONE_PIDFD */
> 		.exit_signal = SIGCHLD,
> 	});
> 
> are easier to read.

That was an accident. I posted from the wrong file. The correct code is:

#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif
#include <errno.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <sched.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#ifndef CLONE_PIDFD
#define CLONE_PIDFD 0x00001000
#endif

#ifndef __NR_clone3
#define __NR_clone3 -1
struct clone_args {
	__aligned_u64 flags;
	__aligned_u64 pidfd;
	__aligned_u64 child_tid;
	__aligned_u64 parent_tid;
	__aligned_u64 exit_signal;
	__aligned_u64 stack;
	__aligned_u64 stack_size;
	__aligned_u64 tls;
};
#endif

static pid_t sys_clone3(struct clone_args *args)
{
	return syscall(__NR_clone3, args, sizeof(struct clone_args));
}

static int wait_for_pid(pid_t pid)
{
	int status, ret;

again:
	ret = waitpid(pid, &status, 0);
	if (ret == -1) {
		if (errno == EINTR)
			goto again;

		return -1;
	}

	if (ret != pid)
		goto again;

	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
		return -1;

	return 0;
}

#define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr)))

int main(int argc, char *argv[])
{
	int pidfd = -1;
	pid_t parent_tid = -1, pid = -1;
	struct clone_args args = {
		/* CLONE_PARENT_SETTID */
		.parent_tid = ptr_to_u64(&parent_tid),
		/* CLONE_PIDFD */
		.pidfd = ptr_to_u64(&pidfd),
		.flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
		.exit_signal = SIGCHLD,
	};

	pid = sys_clone3(&args);
	if (pid < 0) {
		fprintf(stderr, "%s - Failed to create new process\n", strerror(errno));
		exit(EXIT_FAILURE);
	}

	if (pid == 0) {
		printf("Child process with pid %d\n", getpid());
		exit(EXIT_SUCCESS);
	}

	printf("Parent process received child's pid %d as return value\n", pid);
	printf("Parent process received child's pidfd %d\n", pidfd);
	printf("Parent process received child's pid %d as return argument\n",
	       *(pid_t *)args.parent_tid);

	if (wait_for_pid(pid)) {
		fprintf(stderr, "Failed to wait on child process\n");
		exit(EXIT_FAILURE);
	}

	if (pid != parent_tid)
		exit(EXIT_FAILURE);

	close(pidfd);

	return 0;
}

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2019-10-25  9:56 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-25  8:13 clone3() example code Michael Kerrisk (man-pages)
2019-10-25  8:41 ` Christian Brauner
2019-10-25  9:49   ` Aleksa Sarai
2019-10-25  9:56     ` Christian Brauner

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.