tag mp3tag kid3 editar easytag linux fork

linux - kid3 - mp3tag ubuntu



linux fork: previene la herencia de descriptores de archivos (3)

¿Cómo evita que un descriptor de archivo se herede con copia en syscalls de fork () (sin cerrarlo, por supuesto)?

Estoy buscando una forma de marcar un solo descriptor de archivo para que NO sea (copy) heredado por los niños en fork (), algo así como un hack FD_CLOEXEC-like pero para forks (así que una característica FD_DONTINHERIT si quieres). ¿Alguien hizo esto? ¿O miró esto y tiene una pista para que comience?

Gracias

ACTUALIZAR:

Podría usar el __register_atfork de libc

__register_atfork(NULL, NULL, fdcleaner, NULL)

para cerrar los fds en child justo antes de que fork () vuelva. Sin embargo, los fds todavía se están copiando, así que esto me parece un truco tonto. La pregunta es cómo saltarse el dup () - ing en niño de fds innecesarios

Estoy pensando en algunos escenarios cuando se necesitaría un fcntl (fd, F_SETFL, F_DONTINHERIT):

  • fork () copiará un evento fd (por ejemplo, epoll); a veces esto no es necesario, por ejemplo, FreeBSD está marcando el evento kqueue () fd como si fuera un KQUEUE_TYPE y estos tipos de fds no se copiarán en las bifurcaciones (los kqueue fds se omiten explícitamente de ser copiados, si uno quiere usarlo de un niño que debe bifurcar con la tabla fd compartida)

  • fork () copiará 100k fds innecesarios para bifurcar a un niño por hacer algunas tareas intensivas de cpu (suponga que la necesidad de un fork () es probablemente muy baja y el programador no querrá mantener un grupo de niños para algo que normalmente no lo haría ». t pasa

Algunos descriptores que queremos copiar (0,1,2), algunos (¿la mayoría de ellos?) No. Creo que el duping completo está aquí por razones históricas, pero probablemente me equivoque.

Qué tonta suena esto:

  • parche fcntl para admitir el indicador Dontinherit en los descriptores de archivos (no estoy seguro de si el indicador se debe mantener por-fd o en un fdtable fd_set, como los indicadores close-on-exec se mantienen
  • modifique dup_fd () en el kernel para omitir la copia de dontinherit fds, igual que lo hace freebsd para kq fds

considerar el programa

#include <stdio.h> #include <unistd.h> #include <err.h> #include <stdlib.h> #include <fcntl.h> #include <time.h> static int fds[NUMFDS]; clock_t t1; static void cleanup(int i) { while(i-- >= 0) close(fds[i]); } void clk_start(void) { t1 = clock(); } void clk_end(void) { double tix = (double)clock() - t1; double sex = tix/CLOCKS_PER_SEC; printf("fork_cost(%d fds)=%fticks(%f seconds)/n", NUMFDS,tix,sex); } int main(int argc, char **argv) { pid_t pid; int i; __register_atfork(clk_start,clk_end,NULL,NULL); for (i = 0; i < NUMFDS; i++) { fds[i] = open("/dev/null",O_RDONLY); if (fds[i] == -1) { cleanup(i); errx(EXIT_FAILURE,"open_fds:"); } } t1 = clock(); pid = fork(); if (pid < 0) { errx(EXIT_FAILURE,"fork:"); } if (pid == 0) { cleanup(NUMFDS); exit(0); } else { wait(&i); cleanup(NUMFDS); } exit(0); return 0; }

Por supuesto, no puedo considerar esto como un banco real, pero de todos modos:

root@pinkpony:/home/cia/dev/kqueue# time ./forkit fork_cost(100 fds)=0.000000ticks(0.000000 seconds) real 0m0.004s user 0m0.000s sys 0m0.000s root@pinkpony:/home/cia/dev/kqueue# gcc -DNUMFDS=100000 -o forkit forkit.c root@pinkpony:/home/cia/dev/kqueue# time ./forkit fork_cost(100000 fds)=10000.000000ticks(0.010000 seconds) real 0m0.287s user 0m0.010s sys 0m0.240s root@pinkpony:/home/cia/dev/kqueue# gcc -DNUMFDS=100 -o forkit forkit.c root@pinkpony:/home/cia/dev/kqueue# time ./forkit fork_cost(100 fds)=0.000000ticks(0.000000 seconds) real 0m0.004s user 0m0.000s sys 0m0.000s

forkit se ejecutó en una CPU T7500 @ 2.20GHz Dell Inspiron 1520 Intel (R) Core (TM) 2 Duo a 2.20GHz con 4GB de RAM; average_load = 0.00


No hay una forma estándar de hacer esto, que yo sepa.

Si está buscando implementarlo correctamente, probablemente la mejor manera de hacerlo sería agregar una llamada al sistema para marcar el descriptor del archivo como un sys_fork , e interceptar la sys_fork sistema sys_fork (syscall número 2) para que actúe. en esas banderas después de llamar al sys_fork original.

Si no desea agregar una nueva llamada al sistema, podría interceptar sys_ioctl (syscall número 54) y simplemente agregarle un nuevo comando para marcar la descripción de un archivo close-on-fork.

Por supuesto, si puede controlar lo que está haciendo su aplicación, entonces sería mejor mantener las tablas de nivel de usuario de todos los descriptores de archivos que desea cerrar en la bifurcación y llamar a su propio myfork en su lugar. Esto se bifurcaría, luego iría a través de la tabla de nivel de usuario cerrando los descriptores de archivo marcados.

Entonces no tendría que jugar con el kernel de Linux, una solución que probablemente solo sea necesaria si no tiene control sobre el proceso de bifurcación (por ejemplo, si una biblioteca de terceros está haciendo las llamadas de fork() ).


No. Ciérralos tú mismo, ya que sabes cuáles deben cerrarse.


Si se fork con el propósito de llamar a una función exec , puede usar fcntl con FD_CLOEXEC para FD_CLOEXEC el descriptor del archivo una vez que exec :

int fd = open(...); fcntl(fd, F_SETFD, FD_CLOEXEC);

Dicho descriptor de archivo sobrevivirá a una fork pero no a las funciones de la familia de exec .