Read this post in english.
Muchos habrán oido sobre Valgrind para detectar memory leaks (entre otras funciones que posee), pero lamentablemente Valgrind aún no funciona en Solaris SPARC, por lo cual vamos a tener que usar otras herramientas cuando estemos trabajando en un Solaris SPARC. En la documentación de Oracle BRM se menciona Purify pero como hay que pagar licencia vamos a utilizar algo que ya poseea nuestro SO y no tengamos que pagar.
Para detectar memory leaks (referidos a *poid_t y *pin_flist_t) en el CM, lo primero que tenemos que hacer es modificar el pin.conf del CM agregando esta línea:
- - disable_pcm_mempool 1Al agregar esa linea en el pin.conf del CM hemos deshabilitado el pool de memoria que manejan los CMs para procesar flist y poids, ahora la memoria se asigna desde el heap del sistema.
En la documentación online de Oracle podemos ver: To reduce thread contention on malloc calls, CMs include a memory pool mechanism for processing flists and POIDs. When flists and POIDs are allocated memory from a pool, problems with memory leaks are hidden. To detect memory leaks in your CM, before you run Purify or any other diagnostic utilities to test memory usage, disable the memory pool by adding the following entry in the CM pin.conf file so that memory is allocated from the system heap.
(recordar que cuando modificamos el pin.conf del CM, hay que reiniciar el CM para que tome los cambios realizados)
Hay muchas formas para detectar memory leaks. En este post vamos a utilizar Libumem y MDB. En este post explicaré 3 métodos (dejando el más práctico en último lugar, con un ejemplo paso a paso del mismo). La librería libumen solo está disponible en los sistemas Solaris 9 update 3 y superiores (para verificar que sistema estás utilizando: uname -a ).
Método 1
- Ejecutar:
export LD_PRELOAD=libumem.so
- Ejecutar:
export UMEM_DEBUG=audit
- De ser posible poner los puntos 1 y 2 en el .profile para no tener que estar ejecutándolos cada vez que se abre una nueva terminal.
- Compilar la librería fm_pol... con los flags -g y -lumen
- Iniciar el CM.
- Ejecutar el opcode que se quiere probar y ver el pid (process id) del CM que esta ejecutando el opcode.
- En otra terminal ejecutar:
echo "::findleaks -d " | mdb -p pid_cm
Método 2
- Ejecutar:
export LD_PRELOAD=libumem.so
- Ejecutar:
export UMEM_DEBUG=audit
- De ser posible poner los puntos 1 y 2 en el .profile para no tener que estar ejecutándolos cada vez que se abre una nueva terminal.
- Compilar la librería fm_pol... con los flags -g y -lumen
- Iniciar el CM.
- Ejecutar el opcode que se quiere probar y ver el pid (process id) del CM que esta ejecutando el opcode.
- En otra terminal ejecutar:
gcore pid_cm
El comando anterior generará un archivo llamado core.pid_cm - Ejecutar:
mdb core.pid_cm
- Ejecutar:
::findleaks
- En caso de haber memory leaks la salida de ::findleaks nos mostrará cuantos buffers con memory leaks hay.
- De cada buffer podemos obtener el stack trace ejecutando ::bufctl_audit para cada dirección bufctl. Notar que si se han leakeado (palabra inventada) mas de 16K la salida incluirá una lista de esos buffers leakeados incluyendo la cantidad de bytes y la dirección vmem_seg. Se pueden obtener los stack traces para esos buffers ejecutando ::vmem_seg -v para cada dirección vmem_seg.
Método 3
- Ejecutar:
export LD_PRELOAD=libumem.so
- Ejecutar:
export UMEM_DEBUG=audit
- De ser posible poner los puntos 1 y 2 en el .profile para no tener que estar ejecutándolos cada vez que se abre una nueva terminal.
- Compilar la librería fm_pol... con los flags -g y -lumen
- Iniciar el CM.
- Crear un archivo de texto con el flist de entrada del opcode que se quiere probar.
- Compilar testMemory.c con los flags -g y -lumen (al final del post esta el código fuente).
- Ejecutar el programa testMemory con archivo conteniendo el flist de entrada y el opcode que se quiere probar. Por ejemplo: testMemory inFlist.txt PCM_OP_INV_POL_PREP_INVOICE
- El programa se conectará a BRM, ejecutará el opcode con el flist que se recibió y generará un archivo core para el CM que ejecutó el opcode, eso es todo lo que hace el programa (ejecuta el opcode y genera el core).
- Ejecutar:
mdb core.pid_cm
- Ejecutar:
::findleaks
- En caso de haber memory leaks la salida de ::findleaks nos mostrará cuantos buffers con memory leaks hay.
- De cada buffer podemos obtener el stack trace ejecutando ::bufctl_audit para cada dirección bufctl. Notar que si se han leakeado (palabra inventada en este momento) mas de 16K la salida incluirá una lista de esos buffers leakeados incluyendo la cantidad de bytes y la dirección vmem_seg. Se pueden obtener los stack traces para esos buffers ejecutando ::vmem_seg -v para cada dirección vmem_seg.
Ejemplo paso a paso del método 3
- El ejemplo lo hare sobre la fm de invoicing $PIN_HOME/source/sys/fm_inv_pol : fm_inv_pol.so
- Los pasos 1, 2 y 3 ya los tengo hechos en mi ambiente (al ponerlos en el .profile) por lo que no los voy a realizar, pero si mostraré el valor de LD_PRELOAD y UMEM_DEBUG.
- Ahora hay que compilar con los flags especificados: -g y -lumen.
- Se inicial el CM.
- Como el fm que quiero probar es el de invoicng voy a hacer un flist para el opcode PCM_OP_INV_MAKE_INVOICE y lo voy a dejar en el archivo PCM_OP_INV_MAKE_INVOICE.txt. El formato de flist es el mismo que utilizaríamos para el testnap o de Developer Center.
- Compilo el archivo testMemory.c con los flags -g y -lumen
- Ejecuto el programa testMemory con el archivo conteniendo el flist de entrada del opcode y el nombre del opcode: testMemory PCM_OP_INV_MAKE_INVOICE.txt
PCM_OP_INV_MAKE_INVOICE - El programa se encargó de crear una conexión al CM, ver la memoria utilizada por el CM antes de ejecutar el opcode, ejecutar el opcode con el flist que le pasamos, ver la memoria utlizada por el CM despues de utlizar el opcode, generar un archivo core del CM y cerrar la conexión al CM.
- Hasta acá ya tenemos el archivo core para analizar con mdb y buscar memory leaks. En este ejemplo el archivo es: core.27895
- Ejecutamos mdb y luego ::findleaks para ver cuantos buffers con memory leaks hay.
- En este caso hay 10 buffers con memory leaks. Ahora hay que analizar cada uno de esos buffers. De cada buffer podemos obtener el stack trace ejecutando ::bufctl_audit para cada dirección bufctl.
- En el stack del 00635950 vemos que nuestra librería fm_inv_pol.so está dejando memoria leakeada (ya que inventamos una palabra vamos a usarla) en la función fm_inv_pol_utils_memory_leak (primer línea del stack que aparece con el nombre de nuestra librería) al invocar la función pcm_op (última línea antes de que aparezca el nombre de nuestra librería).
- Hasta aquí hemos detectado en que función y ejecutando que cosa es lo que está produciendo el memory leak. Ahora hay que ir al codigo donde se encuentra la función fm_inv_pol_utils_memory_leak, buscar todas las llamadas al PCM_OP (que es donde se está haciendo el malloc que luego no se libera) y ver que se está haciendo con el 5to parámetro de dicha función (el 5to parámetro es el único que reserva memoria en el PCM_OP). Si la variable correspondiente al 5to parámetro (un **pin_flist_t) no se está liberando (mediante un destroy), poniendo en otro flist (mediante un put) entonces ahí tenemos nuestro memory leak.
- Para este ejemplo elegí a propósito el PCM_OP porque he visto muchas veces que el pin_flist_t (el 5to parámetro de la función) donde se arroja el resultado de la ejecución del opcode no se le hace un destroy o un put o que en caso de error no se le hace un destroy y se están produciendo memory leaks.
#include "pcm.h" void PCM_OP( pcm_context_t *pcm_ctxp, int32 opcode, int32 flags, pin_flist_t *in_flistp, pin_flist_t **ret_flistpp, pin_errbuf_t *ebufp);
Si vemos la documentación online sobre el 5to parámetro:ret_flistpp
A pointer to a pointer for passing back the return flist. See the individual opcode manual pages for the return flist specifications. All operations produce a return flist with at least the PIN_FLD_POID field on it. Other fields on the return flist depend on the operation being performed. The return flist is passed back even if an error occurred during the operation. It is the responsibility of the caller to destroy the return flist when it is no longer needed.
- Hasta acá hemos analizado un buffer de los 10 detectados. Analicemos otro, por ejemplo el 0040a3b0:
> 0040a3b0::bufctl_audit ADDR BUFADDR TIMESTAMP THREAD CACHE LASTLOG CONTENTS 40a3b0 4138c0 9ebf65e1425464 1 a8008 0 0 libumem.so.1`umem_cache_alloc+0x210 libumem.so.1`umem_alloc+0x60 libumem.so.1`malloc+0x28 libcmpin.so`pcmmem_malloc_flistflds+0x34 libcmpin.so`pini_flist_grow+0x48 libcmpin.so`pin_flist_create_with_size+0xc4 libcmpin.so`pin_flist_create+0x48 fm_bill_utils.so`fm_bill_utils_search_exchange_rate_from_db+0x420 fm_bill.so`fm_bill_init_config_currency_conversionrates+0x6c fm_bill.so`fm_bill_init+0x1ec libcm_main.so`mainThread+0x323c main+8 _start+0x108 >
- Aquí no se ve la llamada a nuestra librería fm_inv_pol.so, el memory leak esta en la librería fm_inv.so en la función fm_inv_make_invoice_event_search al ejecutar pin_flist_create. De esta librería no tenemos el código fuente, por lo tanto no podemos hacer nada para solucionar el memory leak que está provocando.
- Ya hemos analizado 2 buffers de 10. Los otros 8 quedan de tarea para el hogar. La mecánica es la misma para todos.
- En el próximo post (Detección de memory leaks - Parte II) voy a mostrar como a partir del resultado del ::bufctl_audit podemos obtener en qué línea del código fuente está produciéndose el memory leak.
pin>echo $LD_PRELOAD libumem.so pin>echo $UMEM_DEBUG audit
pin>make all cc -c -g -xcg92 -lumen -lthread -ldl -lpinsys -shared -DFOR_CM -DFM_INV_POL_DLL -I/export/home/pin/7.5/include -I/export/home/pin/7.5/lib -DPCMCPP_CONST_SAFE -DFOR_CM -DFM_INV_POL_DLL fm_inv_pol_config.c fm_inv_pol_init.c fm_inv_pol_common.c fm_inv_pol_format_view.c fm_inv_pol_prep_invoice.c fm_inv_pol_format_invoice.c fm_inv_pol_format_invoice_doc1.c fm_inv_pol_format_invoice_html.c fm_inv_pol_format_invoice_xml.c fm_inv_pol_format_invoice_xslt.c fm_inv_pol_select.c fm_inv_pol_utils.c fm_inv_pol_post_make_invoice.c fm_inv_pol_config.c: fm_inv_pol_init.c: fm_inv_pol_common.c: fm_inv_pol_format_view.c: fm_inv_pol_prep_invoice.c: fm_inv_pol_format_invoice.c: fm_inv_pol_format_invoice_doc1.c: fm_inv_pol_format_invoice_html.c: fm_inv_pol_format_invoice_xml.c: fm_inv_pol_format_invoice_xslt.c: fm_inv_pol_select.c: fm_inv_pol_utils.c: fm_inv_pol_post_make_invoice.c: ld -o /export/home/pin/7.5/lib/fm_inv_pol.so -G -L/export/home/pin/7.5/lib fm_inv_pol_config.o fm_inv_pol_init.o fm_inv_pol_common.o fm_inv_pol_format_view.o fm_inv_pol_prep_invoice.o fm_inv_pol_format_invoice.o fm_inv_pol_format_invoice_doc1.o fm_inv_pol_format_invoice_html.o fm_inv_pol_format_invoice_xml.o fm_inv_pol_format_invoice_xslt.o fm_inv_pol_select.o fm_inv_pol_utils.o fm_inv_pol_post_make_invoice.o -lm -lpsiu_for_cm
pin>make all cc -c -g -xcg92 -lumem -I/export/home/pin/7.5/include testMemory.c CC -o testMemory -g -xcg92 -lumem -I/export/home/pin/7.5/include -L/export/home/pin/7.5/lib -R:/export/home/pin/7.5/lib: -L/export/home/pin/7.5/lib testMemory.o -lportal -lmta -lpinsys -lsocket -lnsl -lgen -lposix4 -lpthread -ldl
pin>testMemory PCM_OP_INV_MAKE_INVOICE.flist PCM_OP_INV_MAKE_INVOICE Conectado a BRM PID VSZ RSS F S SZ STIME TIME %MEM COMMAND 27895 62872 13896 0 S 7859 19:38:34 00:00 0.1 /export/home/pines/pin14/7.5/bin/cm 27793 62872 36664 0 S 7859 19:38:16 00:01 0.1 /export/home/pines/pin14/7.5/bin/cm CM nuevo, pid = 27895 Opcode PCM_OP_INV_MAKE_INVOICE ejecutado Output Flist: # number of field entries allocated 20, used 1 0 PIN_FLD_POID POID [0] 0.0.0.1 /invoice 2751918 0 PID VSZ RSS F S SZ STIME TIME %MEM COMMAND 27895 91544 43320 0 S 11443 19:38:34 00:02 0.2 /export/home/pines/pin14/7.5/bin/cm 27793 62872 36664 0 S 7859 19:38:16 00:01 0.1 /export/home/pines/pin14/7.5/bin/cm Ejecutando: gcore 27895 gcore: core.27895 dumped
pin>mdb core.27895 Loading modules: [ libumem.so.1 libc.so.1 libuutil.so.1 ld.so.1 ] > ::findleaks mdb: [fc000000, fc564000): couldn't read 16384 bytes at fc000000: no mapping for address CACHE LEAKED BUFCTL CALLER 000a8008 1 0040a2e0 libcmpin.so`pcmmem_malloc_flistflds+0x34 000a8008 1 0058da18 libcmpin.so`pcmmem_malloc_flistflds+0x34 000a8008 1 0040a3b0 libcmpin.so`pcmmem_malloc_flistflds+0x34 000a8008 1 005e6220 libcmpin.so`pcmmem_malloc_flistflds+0x34 000a4008 1 0040ab68 libcmpin.so`pcmmem_malloc_flisthdr+0x34 000a4008 1 004001a0 libcmpin.so`pcmmem_malloc_flisthdr+0x34 000a4008 1 005814c8 libcmpin.so`pcmmem_malloc_flisthdr+0x34 000a4008 1 005e6970 libcmpin.so`pcmmem_malloc_flisthdr+0x34 0006c008 1 00635950 libcmpin.so`pcmmem_malloc_poid+0x34 0006c008 1 0064dd40 libcmpin.so`pcmmem_malloc_poid+0x34 ---------------------------------------------------------------------- Total 10 buffers, 2880 bytes
> 00635950::bufctl_audit ADDR BUFADDR TIMESTAMP THREAD CACHE LASTLOG CONTENTS 635950 6319e0 9ebf699f553207 1 6c008 0 0 libumem.so.1`umem_cache_alloc+0x210 libumem.so.1`umem_alloc+0x60 libumem.so.1`malloc+0x28 libcmpin.so`pcmmem_malloc_poid+0x34 libcmpin.so`pcpxdr_poid+0xd0 libcmpin.so`pcpxdr_fld_list+0xe04 libcmpin.so`pcpxdr_op_decode+0x8c libcmpin.so`pcp_receive_no_trans_cleanup+0x128 libcmpin.so`pcm_op_ex+0x9fc libcmpin.so`pcm_op+0x1c fm_inv_pol.so`fm_inv_pol_utils_memory_leak+0x3b0 fm_inv_pol.so`fm_inv_pol_utils_add_fields+0xf0 fm_inv_pol.so`fm_inv_pol_prep_invoice+0x124 fm_inv_pol.so`op_inv_pol_prep_invoice+0xf4 libcmpin.so`cm_pre_pcm_op+0x14f4 >
#include <stdio.h> #include <stdio.h> #include <string.h> #include "pcm.h" #include "pinlog.h" #include <unistd.h> #include <dlfcn.h> #define MAX_PROCESS 256 #define STRING_LENGH 256 //ejecuta el comando recibido por parametro void ejecutar_comando( char *comando); //crea un flist que se encuentra contenido en un archivo pin_flist_t* create_flist_from_file( char *file_name, int64 db, pin_errbuf_t *ebufp, int print); //Obtiene los CMs que se encuentran en ejecucion actualmente void get_CMs_actuales( char array_CMs[MAX_PROCESS][STRING_LENGH]); //Obtiene los CMs que se encuentran en ejecucion actualmente, pero que no estaban en ejecucion antes void get_CMs_nuevos( char array_CMs_anteriores[MAX_PROCESS][STRING_LENGH], char array_CMs[MAX_PROCESS][STRING_LENGH]); //Genero el archivo core para cada uno de los CMs recibidos void generar_cores( char array_CMs[MAX_PROCESS][STRING_LENGH]); int main( int argc, char *argv[]) { pcm_context_t *ctxp; pin_flist_t *out_flistp; pin_flist_t *in_flistp; pin_opcode_t opcode; pin_errbuf_t ebuf; int64 db = 1; char *file_name = NULL; char *opname = NULL; char array_CMs_anteriores[MAX_PROCESS][STRING_LENGH]; char array_CMs_nuevos[MAX_PROCESS][STRING_LENGH]; if(argc != 3){ fprintf(stderr, "\nModo de uso: archivo_flist opcode_name\n\n"); exit(1); } file_name = argv[1]; opname = argv[2]; opcode = pcm_opname_to_opcode(opname); if(opcode == 0){ fprintf(stderr, "\nError, el opcode %s no existe\n\n", opname); exit(1); } PIN_ERR_CLEAR_ERR(&ebuf); //leo el flist que se encuentra en el archivo in_flistp = create_flist_from_file(file_name, db, &ebuf, 0); if (PIN_ERR_IS_ERR(&ebuf)) { fprintf(stderr, "Error al armar el flist del archivo %s\n", file_name); PIN_FLIST_DESTROY_EX(&in_flistp, NULL); exit(1); } if(in_flistp == NULL){ fprintf(stderr, "Error al armar el flist del archivo %s\n", file_name); exit(1); } //Obtengo los CMs que se encuentran en ejecucion actualmente get_CMs_actuales(array_CMs_anteriores); //Me conecto a BRM, lo que generara un nuevo CM PCM_CONNECT(&ctxp, &db, &ebuf); if (PIN_ERR_IS_ERR(&ebuf)) { fprintf(stderr, "Error al ejecutar PCM_CONNECT\n"); PIN_FLIST_DESTROY_EX(&in_flistp, NULL); exit(1); } fprintf(stdout, "\n\nConectado a BRM\n\n"); //Muestro el estado de los CMs antes de ejecutar el opcode ejecutar_comando("ps -eo pid,vsz,rss,f,s,osz,stime,time,pmem,comm | head -1"); ejecutar_comando("ps -eo pid,vsz,rss,f,s,osz,stime,time,pmem,comm | grep $PIN_HOME/bin/cm"); //Obtengo los CMs que se iniciarion despues que la ultima vez que los revise, aqui estara el que ejecutara el opcode get_CMs_nuevos(array_CMs_anteriores, array_CMs_nuevos); //Ejecuto el opcode con el flist del archivo PCM_OP(ctxp, opcode, 0, in_flistp, &out_flistp, &ebuf); PIN_FLIST_DESTROY_EX(&in_flistp, NULL); if (PIN_ERR_IS_ERR(&ebuf)) { fprintf(stderr, "\n\nError ejecutando el opcode %s\n", opname); PIN_ERR_LOG_EBUF(PIN_ERR_LEVEL_ERROR, "main error", &ebuf); PIN_ERR_CLEAR_ERR(&ebuf); } else { fprintf(stdout, "\n\nOpcode %s ejecutado \n", opname); fprintf(stdout, "\nOutput Flist:\n"); PIN_FLIST_PRINT(out_flistp, NULL, &ebuf); } PIN_FLIST_DESTROY_EX(&out_flistp, NULL); fprintf(stdout, "\n\n"); //Muestro el estado de los CMs despues de ejecutar el opcode ejecutar_comando("ps -eo pid,vsz,rss,f,s,osz,stime,time,pmem,comm | head -1"); ejecutar_comando("ps -eo pid,vsz,rss,f,s,osz,stime,time,pmem,comm | grep $PIN_HOME/bin/cm"); //genero los archivos core para todos los CMs nuevos, entre los cuales se encuentra el que ejecuto este opcode generar_cores(array_CMs_nuevos); //cierro el contex PCM_CONTEXT_CLOSE(ctxp, 0, &ebuf); if (PIN_ERR_IS_ERR(&ebuf)) { fprintf(stderr, "Error ejecutando PCM_CONTEXT_CLOSE\n"); exit(1); } return 0; } //crea un flist que se encuentra contenido en un archivo pin_flist_t* create_flist_from_file( char *file_name, int64 db, pin_errbuf_t *ebufp, int print) { char *buffer; char linea[1048]; pin_flist_t *in_flistp = NULL; long length = 0; FILE *file = fopen(file_name, "r"); if (file) { fseek(file, 0, SEEK_END); length = ftell(file) + 1; if(length > 15){ fseek(file, 0, SEEK_SET); buffer = (char*)calloc(length, sizeof(char)); if (buffer != NULL) { while (feof(file) == 0) { fgets(linea, sizeof(linea), file); if(strlen(linea) > 15 && feof(file) == 0 ){ //solo me quedo con las lineas de mas de 15 caracteres strcat(buffer, linea); } } } else { fprintf(stderr, "\nError, calloc de buffer devolvio NULL \n"); } } else { //el archivo debe tener por lo menos los datos de un poid, si es demasiado chico ni eso tiene fprintf(stderr, "\nError, el contenido del archivo no es valido\n"); } fclose(file); } else { fprintf(stderr, "\nError al abrir el archivo %s\n", file_name); return NULL; } if (buffer != NULL) { PIN_STR_TO_FLIST(buffer, db, &in_flistp, ebufp); if(print != 0){ fprintf(stdout, "\nFlist leido del archivo %s\n", file_name); PIN_FLIST_PRINT(in_flistp, NULL, ebufp); } free(buffer); } return in_flistp; } //ejecuta el comando recibido por parametro void ejecutar_comando(char *comando) { char buffer[256]; char *result = NULL; FILE *pipe = popen(comando, "r"); if (!pipe) { fprintf(stderr, "\nError al ejecutar el comando: %s\n", comando); return; } result = (char*)malloc(256*sizeof(buffer)); if(result == NULL){ fprintf(stderr, "\nError, malloc de result devolvio NULL \n"); return; } memset(result, '\0', sizeof(result)); while(!feof(pipe)) { if(fgets(buffer, sizeof(buffer)-1, pipe) != NULL){ strcat(result, buffer); } } pclose(pipe); fprintf(stdout, "%s", result); free(result); } //Obtiene los CMs que se encuentran en ejecucion actualmente void get_CMs_actuales( char array_CMs[MAX_PROCESS][STRING_LENGH]) { char *comando = "ps -eo pid,vsz,rss,f,s,osz,stime,time,pmem,comm | grep $PIN_HOME/bin/cm"; FILE *pipe = popen(comando, "r"); int i = 0; if (!pipe) { fprintf(stderr, "\nError al ejecutar el comando: %s\n", comando); return; } while(!feof(pipe)) { if(fgets(array_CMs[i], sizeof(array_CMs[i])-1, pipe) != NULL){ i++; } if (i >= MAX_PROCESS) { fprintf(stdout, "\n\nSe supero la cantidad de procesos definidos, no se mostraran todos los procesos, solamente %d procesos\n\n", MAX_PROCESS); break; } } pclose(pipe); } //Obtiene los CMs que se encuentran en ejecucion actualmente, pero que no estaban en ejecucion antes void get_CMs_nuevos( char array_CMs_anteriores[MAX_PROCESS][STRING_LENGH], char array_CMs[MAX_PROCESS][STRING_LENGH]) { char *comando = "ps -eo pid,vsz,rss,f,s,osz,stime,time,pmem,comm | grep $PIN_HOME/bin/cm"; FILE *pipe = popen(comando, "r"); char aux[STRING_LENGH]; char *sub_str = NULL; char *str = NULL; char *str_ps = NULL; int i = 0; if (!pipe) { fprintf(stderr, "\nError al ejecutar el comando: %s\n", comando); return; } fprintf(stdout, "\n"); while(!feof(pipe)) { if(fgets(aux, sizeof(aux)-1, pipe) != NULL){ str_ps = strtok_r(aux, " ", &sub_str); if(str_ps != NULL){ int encontrado = 0; for(int j = 0; (j < MAX_PROCESS) && (array_CMs_anteriores[j] != NULL) && (strlen(array_CMs_anteriores[j]) > 0) && (encontrado == 0); j++){ str = strtok_r(array_CMs_anteriores[j], " ", &sub_str); if(strcmp(str_ps, str) == 0){ //es un CM de los anteriories al context open encontrado = 1; } } if(encontrado == 0){ fprintf(stdout, "CM nuevo, pid = %s\n", str_ps); strcpy(array_CMs[i], aux); i++; } } } if (i >= MAX_PROCESS) { fprintf(stdout, "\n\nSe supero la cantidad de procesos definidos, no se mostraran todos los procesos, solamente %d procesos\n\n", MAX_PROCESS); break; } } pclose(pipe); } //Genero el archivo core para cada uno de los CMs recibidos void generar_cores( char array_CMs[MAX_PROCESS][STRING_LENGH]) { char *sub_str = NULL; char *cm_pid = NULL; char comando[20]; for(int i = 0; (i < MAX_PROCESS) && (array_CMs[i] != NULL) && (strlen(array_CMs[i]) > 0); i++){ cm_pid = strtok_r(array_CMs[i], " ", &sub_str); //generando el archivo core para el cm_pid sprintf(comando, "gcore %s", cm_pid); fprintf(stdout, "\n\nEjecutando: %s\n\n", comando); ejecutar_comando(comando); } }
Martín Falconi
No hay comentarios.:
Publicar un comentario