superare i limiti del Sistema Operativo Linux


JonyTut / flickr

JonyTut / Flickr

Oggi si parla di programmazione C e sistema operativo Linux.

Avete mai avuto un problema con il numero dei file descriptor che un’applicazione può aprire?

Solitamente non accade, ma, ammettiamo che per un istante, tra file aperti, socket, semafori, connessioni, ecc., il vostro applicativo C/C++ usi molte risorse e, in alcuni momenti di carico, su un sistema a 32 bit, vada a superare il limite dei 1024 file aperti. Che succede?

Semplice. La vostra applicazione inizia a dare i numeri.

Il Sistema Operativo Linux ha dei parametri per regolare la richiesta di risorse da parte delle applicazioni che manda in esecuzione. Quali sono? Per esempio, come faccio a conoscere il numero massimo di file descriptor che posso aprire in un’applicazione?

Basta dare il comando:

ulimit -n

e la shell restituirà, non so:

1024

A quel punto mi chiedo: e se voglio aumentare detto limite?

Dalla pagina di man di ulimit:

ulimit [-HSTabcdefilmnpqrstuvx [limit]]
Provides  control over the resources available to the shell and to processes started by it, on systems that allow such control. The -H and -S options specify that the hard or soft limit is set for the given resource.  A hard limit cannot be increased by a non-root  user once it is set; a soft limit may be increased up to the value of the hard limit.  If neither -H nor -S is specified, both the soft and hard limits are set.  The value of limit can be a number in the unit specified for the resource or  one of  the  special values hard, soft, or unlimited, which stand for the current hard limit, the current soft limit, and no limit, respectively.  If limit is omitted, the current value of the soft limit of the resource is printed, unless  the  -H  option  is given.   When  more  than  one  resource is specified, the limit name and unit are printed before the value.  Other options are interpreted as follows:
-a     All current limits are reported
-b     The maximum socket buffer size
-c     The maximum size of core files created
-d     The maximum size of a process’s data segment
-e     The maximum scheduling priority (“nice”)
-f     The maximum size of files written by the shell and its children
-i     The maximum number of pending signals
-l     The maximum size that may be locked into memory
-m     The maximum resident set size (many systems do not honor this limit)
-n     The maximum number of open file descriptors (most systems do not allow this value to be set)
-p     The pipe size in 512-byte blocks (this may not be set)
-q     The maximum number of bytes in POSIX message queues
-r     The maximum real-time scheduling priority
-s     The maximum stack size
-t     The maximum amount of cpu time in seconds
-u     The maximum number of processes available to a single user
-v     The maximum amount of virtual memory available to the shell
-x     The maximum number of file locks
-T     The maximum number of threads

If limit is given, it is the new value of the specified resource (the -a option is display only).  If no option is given,  then -f  is  assumed.   Values  are  in  1024-byte increments, except for -t, which is in seconds, -p, which is in units of 512-byte blocks, and -T, -b, -n, and -u, which are unscaled values.  The return status is 0 unless an invalid option or argument is supplied, or an error occurs while setting a new limit.

Se voglio aumentare il limite e poi lanciare l’applicazione posso, sempre in riferimento al famoso numero dei file descriptor, lanciare il comando:

ulimit -n 2048

Siccome questa ha effetto sul SO, sul alcune distribuzioni Linux solo l’utente root può effettuare questa modifica, infatti, provando a dare il comando come utente normale, Linux potrebbe dire:

bash: ulimit: open files: cannot modify limit: Operation not permitted

chiaramente, una volta impostato con il comando ulimit, il limite si perde al primo riavvio della macchina.

Si possono fare un paio di cose. O si agisce a livello di codice, oppure fare lanciare l’applicazione dal demone crond impostando una certa configurazione.

Vediamo i dettagli.

A livello di codice

Basta scrivere il seguente codice C limit.c:

#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
int main()
{
struct rlimit limits;
limits.rlim_cur = limits.rlim_max = 2048;
setrlimit(RLIMIT_NOFILE, &limits);
sleep(300);
return 0;
}

poi si compila con:

gcc limit.c -o limit

e si lancia con:

./limit

Perché ho aggiunto sleep(300) ? Per produrre un ritardo nell’uscita dal programma. Ritardo sufficiente a verificare che la stessa (mentre è in esecuzione) abbia impostato correttamente quel valore usando il comando:

cat /proc/$(pidof limit)/limits

Limit                   Soft Limit    Hard Limit   Units
Max cpu time            unlimited     unlimited    seconds
Max file size           unlimited     unlimited    bytes
Max data size           unlimited     unlimited    bytes
Max stack size          8388608       unlimited    bytes
Max core file size      0             unlimited    bytes
Max resident set        unlimited     unlimited    bytes
Max processes           15686         15686        processes
Max open files          2048          2048         files
Max locked memory       unlimited     unlimited    bytes
Max address space       unlimited     unlimited    bytes
Max file locks          unlimited     unlimited    locks
Max pending signals     15686         15686        signals
Max msgqueue size       819200        819200       bytes
Max nice priority       30            30
Max realtime priority   99            99
Max realtime timeout    unlimited     unlimited    us

In caso di configurazione (non si può/vuole modificare il codice dell’applicazione)

Bisogna agire sul file /etc/security/limits.conf aggiungendo le righe:

*       hard    nofile  2048
*       soft    nofile  2048

e poi si opera su /etc/pam.d/crond aggiungendo la riga:

session    required    pam_limits.so

Che permetterà di superare i limiti default una volta che l’applicazione viene lanciata dal demone crond. Ovviamente l’applicazione non può essere sempre lanciata dal demone crond, quindi va comunque studiato il modo di sfruttare una configurazione particolare. Alcune applicazioni già sono predisposte all’uso di PAM, così si può usare ilfdile /etc/security/limits.conf attraverso il SO stesso. Altre, invece, permettono di farlo attraverso il proprio file di configurazione, perché, chiaramente, nel loro codice sorgente C, invocano un setrlimit(RLIMIT_NOFILE, &limits).

Lascia un commento

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...