Solaris: ¿Qué están haciendo tus threads?

Hace algún tiempo, escribí el post Solaris: Buceando en el Kernel con libkvm sobre cómo podemos utilizar la librería libkvm para crear nuestros propios comandos y que dichos comandos realicen cosas que hasta ahora no podíamos hacer.

No tenemos que perder nunca la perspectiva de que administramos sistemas, no nos dedicamos a crear software, pero creo que un buen administrador de sistemas, debe ser capaz de crear sus propios comandos, Unix tiene miles de comandos y continuamente salen más utilidades que nos ayudan en nuestro día a día, pero hace tiempo ya que he descubierto que siempre se vamos a necesitar algo que no podemos hacer con los comandos convencionales. Este post es meramente educativo, no pretendo que compiléis estos programas y los pongáis en producción, el objetivo es enseñar lo fácil que es, con unos conocimientos mínimos de C y algo del Kernel de Solaris, construir comandos a medida que nos pueden ayudar bastante en nuestro día a día.

Nota :Antes de seguir, sería interesante leer el post Solaris: Buceando en el Kernel con libkvm

Mezclando truss y prstat

Mucha gente utiliza habitualmente las herramientas truss y prstat, ambas son muy potentes si se saben utilizar.

  • truss, permite tracear las señales y las llamadas a sistema que ejecuta un proceso.
  • prstat, devuelve información estadística sobre los procesos que están corriendo en el sistema.

Por ahora solo hemos hablado de procesos, pero actualmente lo que nos vamos a encontrar en casi todos los sistemas son aplicaciones Java que lanzan varias decenas de threads, por lo que debemos saber no qué están haciendo los procesos sino también qué están haciendo los threads de un proceso. Tanto truss como prstat, nos permiten trabajar a nivel de threads. Por ejemplo, utilizando el parámetro -L en el comando prstat.

# prstat -L -p 10206
   PID USERNAME  SIZE   RSS STATE  PRI NICE      TIME  CPU PROCESS/LWPID
 10206 user1  1635M 1499M sleep   11   10   1:39:47 2.1% java/2
 10206 user1  1635M 1499M sleep    0   10   0:02:12 1.3% java/88
 10206 user1  1635M 1499M sleep    0   10   0:02:08 1.3% java/84
 10206 user1  1635M 1499M sleep    0   10   0:02:19 1.3% java/87
 10206 user1  1635M 1499M sleep    0   10   0:02:20 1.3% java/81
 10206 user1  1635M 1499M sleep    0   10   0:02:08 1.2% java/85
 10206 user1  1635M 1499M sleep   10   10   0:02:13 1.2% java/86
 10206 user1  1635M 1499M sleep    0   10   0:02:06 1.2% java/82
 10206 user1  1635M 1499M sleep   10   10   0:02:25 1.2% java/83
 10206 user1  1635M 1499M sleep   10   10   0:01:26 0.5% java/62
 10206 user1  1635M 1499M sleep   13   10   0:00:41 0.2% java/59
 10206 user1  1635M 1499M sleep   59   10   0:00:40 0.2% java/60
 10206 user1  1635M 1499M sleep   27   10   0:01:06 0.2% java/67
 10206 user1  1635M 1499M sleep   18   10   0:00:14 0.1% java/23125
 10206 user1  1635M 1499M sleep   59   10   0:00:46 0.0% java/9
 10206 user1  1635M 1499M sleep   29   10   0:00:00 0.0% java/23440
 10206 user1  1635M 1499M sleep   29   10   0:00:27 0.0% java/44
 10206 user1  1635M 1499M sleep   18   10   0:00:00 0.0% java/23439
 10206 user1  1635M 1499M sleep   29   10   0:00:00 0.0% java/30
 10206 user1  1635M 1499M sleep   29   10   0:00:00 0.0% java/29
 10206 user1  1635M 1499M sleep   29   10   0:00:00 0.0% java/28
 10206 user1  1635M 1499M sleep    0   10   0:00:00 0.0% java/27
 10206 user1  1635M 1499M sleep    0   10   0:00:00 0.0% java/26
 10206 user1  1635M 1499M sleep   29   10   0:00:00 0.0% java/25
 10206 user1  1635M 1499M sleep    0   10   0:00:00 0.0% java/24
 10206 user1  1635M 1499M sleep    0   10   0:00:00 0.0% java/23
 10206 user1  1635M 1499M sleep    0   10   0:00:00 0.0% java/22
 10206 user1  1635M 1499M sleep    0   10   0:00:00 0.0% java/21
 10206 user1  1635M 1499M sleep    0   10   0:00:00 0.0% java/20
 10206 user1  1635M 1499M sleep    0   10   0:00:00 0.0% java/19

Total: 1 processes, 156 lwps, load averages: 3.18, 3.14, 2.92

En el comando truss por defecto nos devuelve el ID del threads en la salida.

# truss  -p 10206
/10:    poll(0x190FFD58, 0, 50)                         = 0
/10:    poll(0x190FFD58, 0, 50)                         = 0
/2:     lwp_cond_wait(0x00038070, 0x00038058, 0x79E7FD30) Err#62 ETIME
/10:    poll(0x190FFD58, 0, 50)                         = 0
/10:    poll(0x190FFD58, 0, 50)                         = 0
/10:    poll(0x190FFD58, 0, 50)                         = 0
/105:   poll(0x0DD79CC8, 27, 10000)                     = 1
/105:   lwp_unpark(122, 1)                              = 0
/122:   lwp_park(0x00000000, 0)                         = 0
/10:    poll(0x190FFD58, 0, 50)                         = 0
/10:    poll(0x190FFD58, 0, 50)                         = 0
/105:   poll(0x0DD79CC8, 27, 10000)                     = 1
...

Sería bastante interesante disponer de un comando que nos permitiese conocer, por un lado los threads que se están ejecutando y qué están haciendo estos threads, una mezcla de los comandos truss y prstat. Este nuevo comando lo podemos programar nosotros mismos utilizando la librería libkvm, podría ser algo parecido a esto.

# lwpstat -p 10206 Pid: 10206     PPid: 7670   Threads: 155
 Args: /bea/jdk142_05/bin/java -server -verbose:gc -ms1280m -mx1280m -Xs
t_tid   time   t_state    wchan/wchan0             sobj_type  #w     t_ts             syscall
----- -------- ------- --------------------------- --------- --- ---------------------------------------------------
   10 00:00:00 SLEEP   0x300.../0x0000000 CV          0 0x3002bba81b8 poll(0x190ffd58, 0x0,...)
  105 00:00:00 SLEEP   0x317.../0x0000000 CV          0 0x395b38f9670 poll(0xdd79cc8, 0x1b,...)
  123 00:00:00 SLEEP   0x302.../0x0000000 CV          0 0x300e5bc2b78 lwp_park(0x0, 0x0,...)
  130 00:00:00 SLEEP   0x32b.../0x0000000 CV          0 0x300818c1050 lwp_park(0x0, 0x0,...)
   64 00:00:00 SLEEP   0x000.../0x395b391 USER        0 0x3021be28e50 lwp_cond_wait(0x10ba220, 0x10ba208, ...)
  115 00:00:00 SLEEP   0x300.../0x0000000 CV          0 0x300418f29d8 lwp_park(0x0, 0x0, ...)
  122 00:00:00 SLEEP   0x300.../0x0000000 CV          0 0x3021be28eb8 lwp_park(0x0, 0x0,...)
   75 00:00:00 SLEEP   0x000.../0x395b391 USER        0 0x3002b81cc38  lwp_cond_wait(0xfe77e8, 0xfe77d0, ...)
  144 00:00:00 SLEEP   0x300.../0x0000000 CV          0 0x3002b820340 read(0x634560,0x634548, ...)
   80 00:00:00 SLEEP   0x0000081167c/0x395b391 USER        0 0x495f627a838 lwp_cond_wait(0x811678, 0x811660, ...)
   76 00:00:00 SLEEP   0x00000fe60cc/0x395b391 USER        0 0x3003214bc08 lwp_cond_wait(0xfe60c8, 0xfe60b0, ...)
    2 00:00:00 SLEEP   0x00000038074/0x395b391 USER        0 0x300013190b0 lwp_cond_wait(0x38070, 0x38058, ...)
   79 00:00:00 SLEEP   0x0000080fc0c/0x395b391 USER        0 0x3002b81d2b8 lwp_cond_wait(0x80fc08, 0x80fbf0, ...)
   77 00:00:01 SLEEP   0x00001256864/0x395b391 USER        0 0x302156b4888 lwp_cond_wait(0x1256860, 0x1256848, ...)
  114 00:00:01 SLEEP   0x32b7824acfe/0x0000000 CV          0 0x3002b81c550 lwp_park(0x0, 0x0, ...)
   78 00:00:01 SLEEP   0x00001256974/0x395b391 USER        0 0x3dd07f86070 lwp_cond_wait(0x1256970, 0x1256958, ...)
  106 00:00:01 SLEEP   0x300630412de/0x0000000 CV          0 0x3021be29810 lwp_park(0x0, 0xdc7bd00, ...)
  131 00:00:01 SLEEP   0x301f83e5b7e/0x0000000 CV          0 0x3002bba88a0 lwp_park(0x0, 0x0, ...)
   86 00:00:01 SLEEP   0x00000fe74ac/0x395b391 USER        0 0x3021be29878 lwp_cond_wait(0xfe74a8, 0xfe7490, ...)
  171 00:00:02 SLEEP   0x3005f13ea1e/0x0000000 CV          0 0x300818c0de0 poll(0x37ff0, 0x0, ...)
   83 00:00:02 SLEEP   0x00000c7cc44/0x395b391 USER        0 0x32bccb88148 lwp_cond_wait(0xc7cc40, 0xc7cc28, ...)
   88 00:00:02 SLEEP   0x00000fe5f6c/0x395b391 USER        0 0x30061483468 lwp_cond_wait(0xfe5f68, 0xfe5f50, ...)
   40 00:00:02 SLEEP   0x000007d0b34/0x395b391 USER        0 0x3020108f668 lwp_cond_wait(0x7d0b30, 0x7d0b18, ...)
   41 00:00:02 SLEEP   0x000007d1724/0x395b391 USER        0 0x300318c1c18 lwp_cond_wait(0x7d1720, 0x7d1708, ...)
   42 00:00:02 SLEEP   0x00000b217d4/0x395b391 USER        0 0x3003e9b0c30 lwp_cond_wait(0xb217d0, 0xb217b8, ...)

72 <1m, 15 <5m, 30 <30m, 3 <1h, 1 <5h, 34 >5h

Tendríamos una comando que nos daría una salida parecida a la de prstat, es decir todos los threads que está ejecutando el proceso, con la llamada a sistema que está ejecutando cada thread. Este comando nos permitiría ver con un sencillo pantallazo, qué están haciendo los threads de nuestro proceso.

El comando lwpstat

El código fuente de nuestro nuevo comando lwpstat es un sencillo programa en C (lwpstat.c), que utiliza algunas de las funciones de la librería libkvm para visualizar qué está haciendo cada uno de los threads de nuestros procesos. El algoritmo es extremadamente sencillo:

for(;;)
       {
       kvm_p=kvm_open()
       ...
       pproc=kvm_getproc(kvm_p,npid)
       ...
       read_thread_info(kvm_p,pproc,nthreads,p_thread_info,nlwp_time)
       ...
       kvm_close(kvm_p);
       ....
       Presentar los datos.
       }

Un bucle en el que se abre el fichero que vamos a leer, en nuestro caso es /dev/kmem, la imagen del espacio de direcciones del Kernel, luego se optiene un puntero a la estructura de datos de nuestro proceso. Mediante la función read_thread_info se lee la información del todos los threads del proceso. Una vez que hemos terminado de leer la información, cerramos el acceso al fichero /dev/kmem con la función kvm_close(). Por último, se presenta la información de los threads. La función encargada de leer la información del thread, únicamente extrae la información de una estrutura de datos de tipo kthread_t, podemos ver como está implementada esta estructura de datos en el fichero /usr/include/sys/thread.h, de todos los campos, nos interesa t_sysnum, que contiene el número de la última llamada a sistema que ha ejecutado el thread.

typedef struct _kthread {
...
        uint_t  t_pctcpu;               /* %cpu at last clock_tick(), binary */
                                        /* point at right of high-order bit */
        short   t_sysnum;               /* system call number */
        kcondvar_t      t_delay_cv;
        kmutex_t        t_delay_lock;
...
}  kthread_t;

Si echáis un ojo al código fuente y al fichero /usr/include/sys/thread.h es sencillo entender qué estamos obteniendo de la estructura kthread_t.

IMPORTANTE: algunos de los datos de la estructura kthread_t están controlados por mutex, en nuestro ejemplo no estamos haciendo uso de dichos mutex, por lo que a veces podemos encontrarnos que no tenemos acceso a dichos datos, la explicación a esta forma de trabajar es sencilla, no queremos que nuestro programa entorpezca la ejecución normal de un proceso, por lo que nos limitamos únicamente a leer la información.

El comando lwpfd

Este es una variante del comando lwpstat, que implementa el acceso a los ficheros. Con lwpfd podemos conocer en cada momento cuales son los ficheros con los que está trabajando un thread en concreto. Todos los threads de un proceso tienen acceso a los descriptores de ficheros del proceso y esto lo podemos conocer utilizando el comando pfiles, lo que no nos ofrece pfiles es el fichero con el que está trabajando cada thread. El algoritmo es exactamente el mismo que el de comando lwpstat.

lwpfd utiliza el campo t_activefd, de la estructura de datos kthread_t. El campo t_activefd es un array con la lista de ficheros activos en el thread.

typedef struct _kthread {
...
        struct _afd     t_activefd;     /* active file descriptor table */
...
}  kthread_t;

Este es un ejemplo de la salida del comando lwpfd.

#lwpfd -p 12006 Pid: 12006     PPid: 10628   Threads: 91
 Args: /bea/jdk142_05/bin/java -server -verbose:gc -Xloggc:/logs
t_tid   time   t_state       syscall
----- -------- ------- --------------------------------------
   20 00:00:00 SLEEP   read(0xeecd0, 0x1, ...)
                 FD 102: R[1] SOCK AF_INET mtime:  Type:SOCK_STREAM L:0.0.0.0:52579 R:192.168.0.1:1521  State:CONNECTED
   21 00:00:00 SLEEP   read(0xeecd0, 0x1, ...)
                 FD 30: R[0] SOCK AF_INET mtime:  Type:SOCK_STREAM L:0.0.0.0:52628  R:192.168.0.1:1521  State:CONNECTED
   26 00:00:00 SLEEP   read(0xeecd0, 0x1, ...)
                 FD 92: R[0] SOCK AF_INET mtime:  Type:SOCK_STREAM L:0.0.0.0:52576  R:192.168.0.1:1521  State:CONNECTED
   33 00:00:00 SLEEP   read(0xeecd0, 0x1, ...)
                 FD 58: R[1] SOCK AF_INET mtime:  Type:SOCK_STREAM L:0.0.0.0:47410  R:192.168.0.1:1521  State:CONNECTED
   35 00:00:00 SLEEP   read(0xeecd0, 0x1, ...)
                 FD 45: R[1] SOCK AF_INET mtime:  Type:SOCK_STREAM L:0.0.0.0:57898  R:192.168.0.1:1521  State:CONNECTED
   36 00:00:00 SLEEP   read(0xeecd0, 0x1, ...)
                 FD 67: R[0] SOCK AF_INET mtime:  Type:SOCK_STREAM L:0.0.0.0:46341  R:192.168.0.1:1521  State:CONNECTED
   39 00:00:00 SLEEP   read(0xeecd0, 0x1, ...)
                 FD 62: R[0] SOCK AF_INET mtime:  Type:SOCK_STREAM L:0.0.0.0:44885  R:192.168.0.1:1521  State:CONNECTED
   40 00:00:00 SLEEP   read(0xeecd0, 0x1, ...)
                 FD 52: R[1] SOCK AF_INET mtime:  Type:SOCK_STREAM L:0.0.0.0:53076  R:192.168.0.1:1521  State:CONNECTED
   42 00:00:00 SLEEP   read(0xeecd0, 0x1, ...)
                 FD 60: R[1] SOCK AF_INET mtime:  Type:SOCK_STREAM L:0.0.0.0:48419  R:192.168.0.1:1521  State:CONNECTED
   54 00:00:00 SLEEP   lwp_mutex_enter(0xee988, 0x1, ...)
   55 00:00:00 SLEEP   lwp_mutex_enter(0xee988, 0x1, ...)
   56 00:00:00 SLEEP   poll(0xee988, 0x1, ...)
   59 00:00:00 SLEEP   lwp_cv_wait(0x10fd748, 0x10fd730, ...)
  880 00:00:00 SLEEP   read(0xeecd0, 0x1, ...)
                 FD 65: R[1] SOCK AF_INET mtime:  Type:SOCK_STREAM L:0.0.0.0:52192  R:192.168.0.1:1521  State:CONNECTED
   10 00:00:00 SLEEP   poll(0x214ffd58, 0x0, ...)
  876 00:00:00 SLEEP   lwp_cv_wait(0x4e2038, 0x4e2020, ...)
   38 00:00:00 SLEEP   read(0x37dd8, 0x0, ...)
                 FD 73: R[1] SOCK AF_INET mtime:  Type:SOCK_STREAM L:0.0.0.0:52190  R:192.168.0.1:1521  State:CONNECTED
   27 00:00:00 SLEEP   read(0xcd0bb0, 0xcd0b98, ...)
                 FD 100: R[1] SOCK AF_INET mtime:  Type:SOCK_STREAM L:0.0.0.0:52569  R:192.168.0.1:1521  State:CONNECTED
   90 00:00:00 SLEEP   accept(0x37dd8, 0x0, ...)
                 FD 42: R[1] SOCK AF_INET mtime:  Type:SOCK_STREAM L:172.16.85.18:8100  R:0.0.0.0:0 State:LISTEN
   32 00:00:00 SLEEP   read(0xeecd0, 0x1, ...)
                 FD 85: R[1] SOCK AF_INET mtime:  Type:SOCK_STREAM L:0.0.0.0:52339  R:192.168.0.1:1521  State:CONNECTED
   37 00:00:00 SLEEP   read(0xeecd0, 0x1, ...)
                 FD 51: R[1] SOCK AF_INET mtime:  Type:SOCK_STREAM L:0.0.0.0:50850  R:192.168.0.1:1521  State:CONNECTED
    9 00:00:00 SLEEP   lwp_cv_wait(0x382f8, 0x382e0, ...)
   67 00:00:00 SLEEP   lwp_cv_wait(0x9a0f68, 0x9a0f50, ...)
   69 00:00:00 SLEEP   lwp_cv_wait(0x48d858, 0x48d840, ...)
    2 00:00:00 SLEEP   lwp_cv_wait(0x37e58, 0x37e40, ...)
    3 00:00:00 SLEEP   lwp_cv_wait(0xedfc0, 0xedfa8, ...)
    4 00:00:00 SLEEP   lwp_cv_wait(0xee710, 0xee6f8, ...)

57 <1m, 8 <5m, 26 <30m, 0 <1h, 0 <2h, 0 >5h

IMPORTANTE: algunos de los datos de la estructura kthread_t están controlados por mutex, en nuestro ejemplo no estamos haciendo uso de dichos mutex, por lo que a veces podemos encontrarnos que no tenemos acceso a dichos datos, la explicación a esta forma de trabajar es sencilla, no queremos que nuestro programa entorpezca la ejecución normal de un proceso, por lo que nos limitamos únicamente a leer la información.

Ficheros

Estos son los distintos ficheros con los que puedes compilar los comando lwpstat y lwpfd.

  • lwpstat.c, código fuente del comando lwpstat
  • lwpfd.c, código fuente del comando lwpfd
  • sysc.c, código fuente con la función encargada de leer la lista de llamadas de sistema del fichero /etc/name_to_sysnum
  • sysc.h, fichero de cabecera para las funciones de sysc.c

Makefile

KBIT= 64
FLAGS = -m$(KBIT)
LIBS = -lkvm
OPTIONS = $(FLAGS) $(LIBS)
BIN =
CC= gcc
all: compile
compile: lwpstat.o lwpfd.o sysc.h sysc.o
        $(CC) -o lwpstat $(OPTIONS) lwpstat.o sysc.o
        $(CC) -o lwpfd $(OPTIONS) lwpfd.o sysc.o

sysc.o: sysc.c
        $(CC) -c sysc.c $(FLAGS) -o sysc.o

lwpstat.o: lwpstat.c sysc.h
        $(CC) -c lwpstat.c $(FLAGS) -o lwpstat.o

lwpfd.o: lwpfd.c sysc.h
        $(CC) -c lwpfd.c $(FLAGS) -o lwpfd.o

Conclusión

Este post, solo pretende ser un ejemplo de las posibilidad que tenemos de acceder a información en nuestro sistema si utilizamos herramientas como la librería libkvm. La verdad es que las posibilidades son infinitas y en entornos donde existen procesos que lanzan threads, conocer qué están haciendo cada uno de los threads es un objetivo importante para nosotros como administradores de sistemas. Herramientas como lwpstat y lwpfd, nos permiten de forma rápida conocer qué están haciendo los threads de un proceso.

En el siguiente ejemplo, podemos ver como hay varios threads intentando acceder a un mutex, por lo que podemos tener un problema de bloqueos.

 Pid: 12006     PPid: 10628   Threads: 91
 Args: /bea/jdk142_05/bin/java -server -verbose:gc -Xloggc:/logs
kvm_read: Error leyendo t_sobj_ops
t_tid   time   t_state    wchan/wchan0             sobj_type  #w     t_ts             syscall
----- -------- ------- --------------------------- --------- --- ------------- --------------------------------------
    2 00:00:00 ONPROC  0x00000000000/0x00000000000 USER        0 0x3004e8c2a28 nosys(0x37e58, 0x37e40, ...)
   10 00:00:00 SLEEP   0x3003f6755be/0x00000000000 CV          0 0x30071dcddb0 poll(0x214ffd58, 0x0, ...)
   52 00:00:04 SLEEP   0x00000037ddd/0x31955844140 USER        0 0x3003214a478 lwp_mutex_enter(0x37dd8, 0x4400, ...)
   91 00:00:04 SLEEP   0x00000037ddd/0x31955844140 USER        0 0x3003214aa90 lwp_mutex_enter(0x37dd8, 0x0, ...)
   25 00:00:04 SLEEP   0x00000037ddd/0x31955844140 USER        0 0x3003ebe7b40 lwp_mutex_enter(0x37dd8, 0x0, ...)
   90 00:00:06 SLEEP   0x00000037ddd/0x31955844140 USER        0 0x3194bbceea0 lwp_mutex_enter(0x37dd8, 0x0, ...)
   12 00:00:06 SLEEP   0x00000037ddd/0x31955844140 USER        0 0x3005f11cbd8 lwp_mutex_enter(0x37dd8, 0x0, ...)
   67 00:00:07 SLEEP   0x00000037ddd/0x31955844140 USER        0 0x3003214a410 lwp_mutex_enter(0x37dd8, 0x4400, ...)
  103 00:00:07 SLEEP   0x00000037ddd/0x31955844140 USER        0 0x3021be294d0 lwp_mutex_enter(0x37dd8, 0x0, ...)
   54 00:00:07 SLEEP   0x00000037ddd/0x31955844140 USER        0 0x3006699db38 lwp_mutex_enter(0x37dd8, 0x0, ...)
   13 00:00:07 SLEEP   0x000000380c5/0x31955844140 USER        0 0x3005f11cde0 lwp_mutex_enter(0x380c0, 0x1, ...)
   15 00:00:07 SLEEP   0x00000037ddd/0x31955844140 USER        0 0x3020108f120 lwp_mutex_enter(0x37dd8, 0x0, ...)
   17 00:00:07 SLEEP   0x000000380c5/0x31955844140 USER        0 0x3003f3a80e0 lwp_mutex_enter(0x380c0, 0x1, ...)
   19 00:00:07 SLEEP   0x000000ef285/0x31955844140 USER        0 0x301010a31e0 lwp_mutex_enter(0xef280, 0x1, ...)
   20 00:00:07 SLEEP   0x000000ef285/0x31955844140 USER        0 0x3005705d328 lwp_mutex_enter(0xef280, 0x1, ...)
   21 00:00:07 SLEEP   0x000000380c5/0x31955844140 USER        0 0x3026cdf8e48 lwp_mutex_enter(0x380c0, 0x1, ...)
   23 00:00:07 SLEEP   0x000000380c5/0x31955844140 USER        0 0x3001431f878 lwp_mutex_enter(0x380c0, 0x1, ...)
   24 00:00:07 SLEEP   0x000000380c5/0x31955844140 USER        0 0x3002bba8f20 lwp_mutex_enter(0x380c0, 0x1, ...)
   26 00:00:07 SLEEP   0x000000ef285/0x31955844140 USER        0 0x3000ad43400 lwp_mutex_enter(0xef280, 0x1, ...)
   27 00:00:07 SLEEP   0x000000380c5/0x31955844140 USER        0 0x319591a04f8 lwp_mutex_enter(0x380c0, 0x1, ...)
   29 00:00:07 SLEEP   0x000000380c5/0x31955844140 USER        0 0x32b7669d318 lwp_mutex_enter(0x380c0, 0x1, ...)
   30 00:00:07 SLEEP   0x000000ef285/0x31955844140 USER        0 0x5b8de62b2b0 lwp_mutex_enter(0xef280, 0x1, ...)
   31 00:00:07 SLEEP   0x000000380c5/0x31955844140 USER        0 0x3005705dbb0 lwp_mutex_enter(0x380c0, 0x1, ...)
   33 00:00:07 SLEEP   0x000000380c5/0x31955844140 USER        0 0x3002b81cb68 lwp_mutex_enter(0x380c0, 0x1, ...)
   35 00:00:07 SLEEP   0x000000380c5/0x31955844140 USER        0 0x30056c1a4e0 lwp_mutex_enter(0x380c0, 0x1, ...)
   39 00:00:07 SLEEP   0x000000380c5/0x31955844140 USER        0 0x3026cdf9600 lwp_mutex_enter(0x380c0, 0x1, ...)
   42 00:00:07 SLEEP   0x00000037ec4/0x31955844140 USER        0 0x3026cdf9b48 lwp_cv_wait(0x37ec0, 0x37ea8, ...)

Voy a intentar seguir desarrollando estos comandos, por lo que agradecería cualquier, consejo o idea que se te ocurra.