Showing posts with label IPC. Show all posts
Showing posts with label IPC. Show all posts

Friday, May 12, 2017

Daemons

Fortunately, as a good Unix system, Solaris supports easy daemon creation by encapsulating all the necessary steps into a single system function called daemon(3C). Thus the whole process of becoming a daemon is greatly simplified when compared to the traditional / legacy approach:

#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h> 

#include <cerrno> 
#include <cstdlib> 
#include <cstdarg> 

#include "toolbox.hxx"

void error( toolbox::log & log, const char * message )
{
  int code = errno;
  log.write( "ERROR: %s (%d)\n", message, code );
  ::exit( EXIT_FAILURE );
}

int main( )
{
  toolbox::log log( "trace.log" );

  if ( ! log.open() )
    return EXIT_FAILURE;

  log.write( "Starting up...\n" );

  if ( ::daemon( 0, 0 ) < 0 )
    error( log, "Couldn't become a daemon." );

  log.write( "Successfully became a daemon!\n" );
 
  
  ::umask( 0 );
 
  const int seconds = 30;
  log.write( "Resting for %d seconds...\n", seconds );
  ::sleep( seconds );

  log.write( "Bye cruel world!\n\n" );
  log.close();

  return EXIT_SUCCESS;
}


A typical log output could be similar to:

$ cat trace.log
[2017-05-12 16:29:11] Starting up...
[2017-05-12 16:29:11] Successfully became a daemon!
[2017-05-12 16:29:11] Resting for 30 seconds...
[2017-05-12 16:29:41] Bye cruel world!


It may be interesting to take a look under the hood at the system calls encapsulated by daemon(3C) in order to compare it with the traditional / legacy approach:

$ truss -f ./daemon-01
...
... getcwd("/...", 1024) = 0
... open("/.../trace.log", O_WRONLY|O_APPEND|O_CREAT, 0640) = 3

...
3155:    write(3, " [ 2 0 1 7 - 0 5 - 1 2  ".., 22) = 22
3155:    write(3, " S t a r t i n g   u p .".., 15) = 15
...
3155:    forkx(0)                                   = 3156
 

3155:    _exit(0)
... 
3156:    forkx()        (returning as child ...)    = 3155
3156:    getpid()                                   = 3156 [3155]
...
3156:    setsid()                                   = 3156
...
3156:    forkx(0)                                   = 3158
3156:    _exit(0)
...
3158:    forkx()        (returning as child ...)    = 3156
3158:    getpid()                                   = 3158 [1]
...
3158:    chdir("/")                                 = 0

...
3158:    open("/dev/null", O_RDWR)                  = 4
3158:    fcntl(4, F_DUP2FD, 0x00000000)             = 0
3158:    fcntl(4, F_DUP2FD, 0x00000001)             = 1
3158:    fcntl(4, F_DUP2FD, 0x00000002)             = 2
3158:    close(4)                                   = 0
...
3158:    write(3, " [ 2 0 1 7 - 0 5 - 1 2  ".., 22) = 22
3158:    write(3, " S u c c e s s f u l l y".., 30) = 30
...

3158:    umask(0)                                   = 022
...
3158:    write(3, " [ 2 0 1 7 - 0 5 - 1 2  ".., 22) = 22
3158:    write(3, " R e s t i n g   f o r  ".., 26) = 26
3158:    nanosleep(...) (sleeping...)
3158:    nanosleep(...) = 0
...
3158:    write(3, " [ 2 0 1 7 - 0 5 - 1 2  ".., 22) = 22
3158:    write(3, " B y e   c r u e l   w o".., 18) = 18
3158:    close(3)                                   = 0
...
3158:    _exit(0)

   

Thursday, May 11, 2017

Daemons - 1st steps

In the very start of the endeavor to the daemons' underground world I thought it would be inevitable to be acquainted with a few, perhaps new, essential concepts about processes in terms of how they are collected within the system. So I set out to knowing more about sessions and process groups. It was very instructive as a ground to better undrestanding the necessary steps to turn an ordinary process into a daemon in the traditional way. So, without further words, in essence, the main() function of a Solaris C++ program (or application) that is (or becomes) a daemon in the traditional way is:

#include <sys/types.h> 
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <cerrno> 
#include <cstring>
#include <csignal> 
#include <cstdlib>
#include <cstdio>  
#include <cstdarg>  

#include <string>
#include <iostream>

#include "toolbox.hxx"

int main()
{
  // Some other log file or even syslog could be better.
  // This is just for illustrational purposes.

  // The full implementation is elsewhere. 
  toolbox::log log( "trace.log" );

  if ( log.open() )
    std::cout
       << "Log file: "
       << log.filename
       << std::endl;
  else
  {
    std::cout
       << "FAILURE"
       << std::endl;

    ::exit( EXIT_FAILURE );
  }
  

  // This function does all the "magic"!
  daemon( log );

  log.write( "Finally, success! I'm a daemon!\n" );

  const int seconds = 30;
  log.write( "Resting for %d seconds...\n", seconds );
  ::sleep( seconds );

  log.write( "Bye cruel world!\n\n" );
  log.close();

  return EXIT_SUCCESS;
}


Now let me show the magical :-) daemon() function:

// Little helper...
void error( const toolbox::log & log, const char * msg, ... )
{

  int code = errno;

  va_list ap;
  va_start( ap, msg );

  // MT-safe if setlocale(3C) not called
  // Hence, possbily a serious limitation!
  // More advanced C++ to the rescue!

  char * buffer = 0;
  ::vasprintf( &buffer, msg, ap );
  log.write( "ERROR: %s (%s)\n", buffer, ::strerror(code) );
  ::free( buffer );

  va_end( ap );


  ::exit( EXIT_FAILURE );
}

void daemon( toolbox::log & log )
{
  if ( ! log.write( "\n\nTrying to \"become\" daemon ...\n\n" ) )
    ::exit( EXIT_FAILURE );

  pid_t pid;

  // Creates a new process in the same process group.
  // Sure is the new process is NOT a process group leader.
  // The new process will be entitled to create a new session.

  if ( ( pid = ::fork() ) < 0 )
    error( log, "1st call to fork()" );
  else if ( pid > 0 )
  {
    log.write( "Bye 1st generation descendant!\n" );
    log.write( "PID %d to become a daemon!\n\n", pid );
    ::exit( EXIT_SUCCESS );
  }

  // Creates a new session, effectively
  // disassociating from the controlling terminal.

  if ( ::setsid() < 0 )
    error( log, "setsid()" );

  // The SIGHUP does not apply to me anymmore.
  // There's no controlling terminal after all!
 
  if ( ::sigignore( SIGHUP ) )
    error( log, "sigignore()" ); 


  // Creates another new process in the new process group.
  // Sure is the new process is NOT a process group leader.
  // The new process won't EVER get a controlling terminal.

  if ( ( pid = ::fork() ) < 0 )
    error(  log, "2nd call to fork()" );
  else if ( pid > 0 )
  {
    log.write( "Bye 2nd generation descendant!\n" );
    log.write( "PID %d to become a daemon!\n\n", pid );
    ::exit( EXIT_SUCCESS );
  }

  //
  // Finally! Almost there...
  //


  // Initially assures full access to daemon's own files.
  // Later, should be diligently and temporarily set to 007,
  // specially before library calls that involve files.

  ::umask( 0 );

  // Changes to the selected working directory
  // or at least to / so any unmounts should succeed.

  // After this call don't forget to specify full paths!
  if ( ::chdir( "/" ) < 0 )
    error( log, "chdir()" );


  {
    // Makes sure there's no left over open files.
    log.close();
    ::fcloseall();

    // Mute all the standard files.
    const int std_stream[] =
    {
      ::open( "/dev/null", O_RDWR ), // stdin
      ::dup2( 0, 1 ),                // stdout
      ::dup2( 0, 2 )                 // stderr
    };

    if ( ! log.open() )
      exit( EXIT_FAILURE );

    // Double-check muted descriptors are 0, 1 and 2.
    for ( auto i=0; i<3; i++ )
      if ( std_stream[ i ] != i )
        error( log, "Muting standard files." );
  }
}


A log file produced by running this daemon could be:
 
$ cat trace.log
[2017-05-11 16:29:29]
 

Trying to "become" daemon ...

[2017-05-11 16:29:29] Bye 1st generation descendant!
[2017-05-11 16:29:29] PID 2508 to become a daemon!

[2017-05-11 16:29:29] Bye 2nd generation descendant!
[2017-05-11 16:29:29] PID 2509 to become a daemon!

[2017-05-11 16:29:29] Finally, success! I'm a daemon!
[2017-05-11 16:29:29] Resting for 30 seconds...
[2017-05-11 16:29:59] Bye cruel world!

   
The above approach, although traditional is not the recommended one. Nevertheless it's still possible to catch once in a while some daemons logs in SMF logs which reveal they could only have been programmed the old way...
  

Saturday, April 22, 2017

Sessions & Process Groups

In the very start of the endeavor to the daemons' underground world it's inevitable to be acquainted with a few, perhaps new, essential concepts about processes in terms of how they are collected within the system.

Without further digressions, processes are collected into process groups. But there's an elaboration on top of this leading to another concept called sessions, which is associated to the historical concept of job control from a time lacking the pletora of GUI terminals if not, perhaps, just the rare and crude xterm which some ancient seems to inconditionally love.

Although not really a big mistery, the descriptions about these concepts (process groups, sessions and their related) seems unecessarily convoluted in Intro(2) and termio(7I), which can partially obfuscate understanding its central apparatus. My intention is, thus, to address these obstacules by attempting to streamline some ideas and clarify some of these concepts definitions and descriptions:

PROCESS GROUP
A collection of processes that begins when created by a given process which is thereof defined as its process group leader. The process group ends when the last process in the process group ends of leaves the process group.

During its lifetime it's uniquely identified by a positive integer called the process group ID (PGID), which exactly matches the process ID (PID) of its process group leader and furnishes a way of signaling all its member processes as a whole.

Any process that is not a process group leader may create a new process group or a new session (becoming itself the process group leader and, eventually, the session leader of the newly created entity) or yet may join another process group in the same session.

Each process in the system is a member of a single process group and every newly created process joins the process group and session of its parent (process).
SESSION
A collection of process groups that begins when created by a given process which is thereof defined as its session leader. The session ends when the last process in the session ends of leaves the session

During its lifetime it's uniquely identified by a positive integer called the session ID (SID), which exactly matches the process ID (PID) of its original session leader. The original session leader is also the process group leader for the session's originally first process group, hence its process ID (PID) matches its session ID (SID) and its process group ID (PGID) and, as such, the session ID (SID) also matches its originally first process group ID (PGID).

A session is capable of being biunivocally (one-to-one) associated to a terminal (the controlling terminal, /dev/tty according to tty(7D)) by the session leader (the controlling process) which establishes the connection. As sessions are inherited by new processes created within it, so are the controlling terminals, although this association can be broken if these new processes establish a new session (setsid(2)). The controlling terminal can send/handle certain (typically quit and interrupt) signals to the process groups in the (controlling process') session that, in general, will cause them to stop, unless they have made arrangements to mask this out or are orphaned process groups.

Orphaned process groups are those that share the controlling terminal but whose processes' parents do not belong to any other process group in the same session.

Among the process groups in the session, the controlling terminal will distinguish one of them as the foreground process group, thereby exclusively granting it certain terminal access prerrogatives, and treat all the other process groups in that (controlling process') session as background process groups. By default, the controlling process' (session leader's) process group is assigned as the foreground process group.
 
As for a real world example of a few of these concepts in action applied to a daemon creation you may be interested in browsing the output from truss applied to a sample daemon creation code around the fork() and setsid() system calls and associated PIDs and PPIDs numbers.
 

Friday, April 21, 2017

Daemons listing

Without entering into any further detail about what a daemon is, I'll just show how to list them under a privileged (root) Solaris terminal by means of the standard shell command ps(1):

# ps -o user,uid,pid,ppid,pgid,sid,tty,args -t '?' \
    |(IFS=''; read H; echo "$H"; sort -k5 -k3 \
    |grep filtering_options account )
 
    USER   UID   PID  PPID  PGID   SID TT COMMAND
    root     0     1     0     0     0 ?  /usr/sbin/init
    root     0     3     0     0     0 ?  fsflush
    root     0     7     0     0     0 ?  intrd
    root     0     6     0     0     0 ?  kmem_task
    root     0     2     0     0     0 ?  pageout
    root     0     9     0     0     0 ?  postwaittq
    root     0     0     0     0     0 ?  sched
    root     0     8     0     0     0 ?  vmtasks
    root     0   770     0     0     0 ?  zpool-depot
    root     0   788     0     0     0 ?  zpool-export
    root     0     5     0     0     0 ?  zpool-rpool
    root     0    96     1    13    13 ?  /lib/svc/bin/...
    root     0    13     1    13    13 ?  /lib/svc/bin/svc.startd
    root     0   751     1    13    13 ?  /lib/svc/method/iscsid
    root     0  1862  1353    13    13 ?  /usr/lib/...
    root     0  1353  1341    13    13 ?  /usr/lib/...
    root     0   106     1    13    13 ?  /usr/lib/pfexecd
    root     0   155     1    13    13 ?  /usr/lib/rad/rad -sp
    root     0   164     1    13    13 ?  /usr/lib/rad/rad -sp
    root     0  1341     1    13    13 ?  /usr/sbin/gdm-binary
    root     0    15     1    15    15 ?  /lib/svc/bin/...
  netcfg    17    42     1    42    42 ?  /lib/inet/netcfgd
  netadm    16    45     1    45    45 ?  /usr/sbin/ibmgmtd
   dladm    15    53     1    53    53 ?  /usr/sbin/dlmgmtd
  netadm    16    66     1    66    66 ?  /lib/inet/ipmgmtd
  daemon     1    74     1    74    74 ?  /lib/crypto/kcfd
    root     0    84     1    83    83 ?  /lib/inet/in.mpathd
  daemon     1   149     1   149   149 ?  /usr/lib/utmpd
    root     0   178     1   178   178 ?  /usr/sbin/vbiosd
    root     0   185     1   185   185 ?  /usr/lib/zones/...
    root     0   200     1   200   200 ?  /usr/lib/sysevent/...
    root     0   332     1   332   332 ?  /usr/lib/dbus-daemon ...
    root     0   430     1   430   430 ?  /usr/lib/devfsadm/...
  netadm    16   648     1   648   648 ?  /lib/inet/nwamd
    root     0   688     1   688   688 ?  /usr/lib/picl/picld
    root     0   757     1   757   757 ?  /usr/lib/inet/ntpd ...
    root     0   786     1   786   786 ?  /usr/sbin/nscd
  daemon     1   800     1   800   800 ?  /usr/sbin/rpcbind
    root     0   813     1   813   813 ?  /usr/lib/inet/in.ndpd
    root     0   842     1   840   840 ?  /opt/VirtualBox/...
    root     0   843     1   843   843 ?  /usr/lib/inet/...
    root     0   856     1   856   856 ?  /usr/lib/hotplugd
    root     0   860     1   860   860 ?  /usr/lib/autofs/...
    root     0   862   860   860   860 ?  /usr/lib/autofs/...
    root     0   866     1   865   865 ?  /usr/sbin/...
    root     0   870     1   870   870 ?  /usr/sbin/cron
    root     0   876     1   876   876 ?  /usr/lib/hal/...
    root     0   899   878   876   876 ?  /usr/lib/hal/...
    root     0   895   878   876   876 ?  /usr/lib/hal/...
    root     0   977   878   876   876 ?  /usr/lib/hal/...
    root     0  1160   878   876   876 ?  /usr/lib/hal/...
    root     0  1184   878   876   876 ?  /usr/lib/hal/...
    root     0  1206   878   876   876 ?  /usr/lib/hal/...
    root     0  1219   878   876   876 ?  /usr/lib/hal/...
    root     0  1236   878   876   876 ?  /usr/lib/hal/...
    root     0   878   876   876   876 ?  hald-runner
    root     0   942     1   941   941 ?  /usr/lib/ssh/sshd
    root     0   983     1   983   983 ?  /usr/sbin/syslogd
    root     0  1019     1   987   987 ?  /usr/sbin/auditd
   smmsp    25  1005     1  1005  1005 ?  /usr/lib/inet/...
    root     0  1006     1  1006  1006 ?  /usr/lib/inet/...
    root     0  1024     1  1024  1024 ?  /usr/lib/fm/fmd/fmd
    root     0  1126     1  1125  1125 ?  /usr/bin/python2.7 ...
    root     0  1140     1  1140  1140 ?  /usr/sbin/cupsd -C ...
noaccess 60002  1228     1  1228  1228 ?  /usr/lib/fm/notify/...
    root     0  1232     1  1232  1232 ?  /usr/lib/devchassis/...
noaccess 60002  1234     1  1234  1234 ?  /usr/lib/fm/notify/...
    root     0  1349     1  1348  1348 ?  /usr/lib/rmvolmgr -s
     ocm    62  1639     1  1639  1639 ?  /usr/lib/ocm/ccr/...
     gdm    50  1652     1  1649  1649 ?  /usr/bin/dbus-launch
...


A basic description of each chosen column is on the aforementioned manpage, but it was driven by an interest towards daemon programming. One will note that the main filtering criteria is the absence ('?') of a controlling terminal (TT) and that the output was sorted first by process groups (PGID) and then by process ids (PID). Perhaps one will also note (with the help of Intro(2) manpage) that in this listing each process is a member of the first process group in/of each session because its PGID and SID are equal.
    

Tuesday, June 18, 2013

DISM run sample 3.0

This is a sample run for DISM of the shared memory code sample 3.0:

In an attempt to better demonstrate the presumable advantage of DISM, please, consider the following changes in the original sample source code 3.0:
  
037:     std::size_t const size =
         12UL * 1024UL * 1024UL * 1024UL;
 
051:         void * p = ::shmat( id, 0, SHM_PAGEABLE );
 
063:             if ( ::mlock( p, size / 4 ) == 0 )
 
069:                 ::memset( p, '*', size / 2 );
 
075:                 switch ( ::munlock( p, size / 4 ) )
  

$ getent user_attr 
...::::defaultpriv=basic,proc_lock_memory;...
  
$ swap -lh; swap -sh
swapfile             dev    swaplo   blocks     free
/dev/swap             -         4K     4.0G     3.9G
total: 500M allocated + 178M reserved = 676M used, 18G available

$ ipcs -mA
IPC status ...
T ... KEY ... NATTCH       SEGSZ CPID ... ISMATTCH     PROJECT
Shared Memory:

$ zonestat 1 1
Collecting data for first interval...
Interval: 1, Duration: 0:00:01
SUMMARY  Cpus/Online: 24/24   PhysMem: 23.9G  VirtMem: 27.9G
          ---CPU----  --PhysMem-- --VirtMem-- --PhysNet--
     ZONE  USED %PART  USED %USED  USED %USED PBYTE %PUSE
  [total]  0.32 1.37% 8355M 34.0% 10.0G 35.9%  396K 0.01%
 [system]  0.32 1.36% 8274M 33.6%  9.9G 35.5%     -     -
      ...  0.00 0.00% 81.0M 0.33%  116M 0.40%   228 0.00%

Getting shared memory.
Press <ENTER> to continue...
Success!


$ swap -lh; swap -sh
swapfile             dev    swaplo   blocks     free
/dev/swap             -         4K     4.0G     3.9G
total: 500M allocated + 12G reserved = 13G used, 5.9G available

$ ipcs -mA
IPC status ...
T ... KEY ... NATTCH       SEGSZ
CPID ... ISMATTCH     PROJECT
Shared Memory:
m ... 0x1 ...      0 12884901888 3832 ...        0 group.staff

$ zonestat 1 1
Collecting data for first interval...
Interval: 1, Duration: 0:00:01
SUMMARY     Cpus/Online: 24/24   PhysMem: 23.9G  VirtMem: 27.9G
          ---CPU----  --PhysMem-- --VirtMem-- --PhysNet--
     ZONE  USED %PART  USED %USED  USED %USED PBYTE %PUSE
  [total]  0.26 1.11% 8378M 34.1% 22.0G 78.8%  711K 0.02%
 [system]  0.26 1.10% 8296M 33.7%  9.9G 35.5%     -     -
      ...  0.00 0.00% 82.5M 0.33% 12.1G 43.2%   228 0.00%

$ prstat -c -p 3832 1 1
Please wait...
 PID USERNAME  SIZE   RSS ...     
3832 ...      5140K 2176K ...
...

Attaching to shared memory.
Press <ENTER> to continue...
Success!


$ swap -lh; swap -sh
swapfile             dev    swaplo   blocks     free
/dev/swap             -         4K     4.0G     3.9G
total: 492M allocated + 12G reserved = 13G used, 5.9G available

$ ipcs -mA
IPC status ...
T ... KEY ... NATTCH       SEGSZ CPID ... ISMATTCH     PROJECT
Shared Memory:
m ... 0x1 ...      1 12884901888 3832 ...        1 group.staff

$ zonestat 1 1
Collecting data for first interval...
Interval: 1, Duration: 0:00:01
SUMMARY  Cpus/Online: 24/24   PhysMem: 23.9G  VirtMem: 27.9G
          ---CPU----  --PhysMem-- --VirtMem-- --PhysNet--
     ZONE  USED %PART  USED %USED  USED %USED PBYTE %PUSE
  [total]  0.26 1.10% 8391M 34.1% 22.0G 78.8%   534 0.00%
 [system]  0.26 1.09% 8308M 33.8%  9.9G 35.5%     -     -
      ...  0.00 0.00% 82.6M 0.33% 12.1G 43.3%   432 0.00%

$ prstat -c -p 3832 1 1
Please wait...
 PID USERNAME  SIZE   RSS ...     
3832 ...        12G 2176K ...
...

$ pmap -x 3832 | head
3832:    ./shm_v04
         Address   Kbytes RSS ... Locked Mode  Mapped File
0000000000400000        8   8 ...      - r-x-- shm_v04
0000000000411000        8   8 ...      - rw--- shm_v04
0000000000413000      160
  68 ...      - rw---  [ heap ]
FFFF80FC80000000 12582912   - ...      - rwxs-  [ dism ... ]

...

Locking shared memory.
Press <ENTER> to continue...
Success!


$ swap -lh; swap -sh
swapfile             dev    swaplo   blocks     free
/dev/swap             -         4K     4.0G     3.9G
total: 3.5G allocated + 9.2G reserved = 13G used, 2.9G available

$ ipcs -mA
IPC status ...
T ... KEY ... NATTCH       SEGSZ CPID ...  ISMATTCH     PROJECT
Shared Memory:
m ... 0x1 ...      1 12884901888 3832 ...         1 group.staff

$ zonestat 1 1
Collecting data for first interval...
Interval: 1, Duration: 0:00:01
SUMMARY  Cpus/Online: 24/24   PhysMem: 23.9G  VirtMem: 27.9G
          ---CPU----  --PhysMem-- --VirtMem-- --PhysNet--
     ZONE  USED %PART  USED %USED  USED %USED PBYTE %PUSE
  [total]  0.29 1.23% 11.1G 46.6% 25.0G 89.5%  704K 0.00%
 [system]  0.29 1.22% 8308M 33.8% 12.9G 46.2%     -     -
      ...  0.00 0.00% 3154M 12.8% 12.1G 43.3%  1347 0.00%

$ prstat -c -p 3832 1 1
Please wait...
 PID USERNAME  SIZE   RSS ...     
3832 ...        12G 3074M ...
...

$ pmap -x 3832 | head
3832:    ./shm_v04
         Address   Kbytes     RSS ...  Locked Mode  Mapped File
0000000000400000        8       8 ...       - r-x-- shm_v04
0000000000411000        8       8 ...       - rw--- shm_v04
0000000000413000      160      68 ...       - rw---  [ heap ]
FFFF80FC80000000 12582912 3145728 ... 3145728 rwxs-  [ dism ... ]
...

Using shared memory.
Press <ENTER> to continue...
Success!


$ swap -lh; swap -sh
swapfile             dev    swaplo   blocks     free
/dev/swap             -         4K     4.0G     3.9G
total: 6.5G allocated + 6.2G reserved = 13G used, 2.9G available

$ ipcs -mA
IPC status ...
T ... KEY ... NATTCH       SEGSZ CPID ... ISMATTCH     PROJECT
Shared Memory:
m ... 0x1 ...      1 12884901888 3832 ...        1 group.staff

$ zonestat 1 1
Collecting data for first interval...
Interval: 1, Duration: 0:00:01
SUMMARY  Cpus/Online: 24/24   PhysMem: 23.9G  VirtMem: 27.9G
          ---CPU----  --PhysMem-- --VirtMem-- --PhysNet--
     ZONE  USED %PART  USED %USED  USED %USED PBYTE %PUSE
  [total]  0.27 1.13% 14.1G 59.1% 25.0G 89.5%   228 0.00%
  
 [system]  0.27 1.12% 8309M 33.8% 12.9G 46.2%     -     -
      ...  0.00 0.00% 6225M 25.3% 12.1G 43.3%   228 0.00%

$ prstat -c -p 3832 1 1
Please wait...
 PID USERNAME  SIZE   RSS ...     
3832 ...        12G 6146M ...
...

$ pmap -x 3832 | head
3832:    ./shm_v04
         Address   Kbytes     RSS ...  Locked Mode  Mapped File
0000000000400000        8       8 ...       - r-x-- shm_v04
0000000000411000        8       8 ...       - rw--- shm_v04
0000000000413000      160      68 ...       - rw---  [ heap ]
FFFF80FC80000000 12582912 6291456 ... 3145728 rwxs-  [ dism ... ]
...

Unlocking shared memory.
Press <ENTER> to continue...
Success!


$ swap -lh; swap -sh
swapfile             dev    swaplo   blocks     free
/dev/swap             -         4K     4.0G     3.9G
total: 6.5G allocated + 6.2G reserved = 13G used, 5.9G available

$ ipcs -mA
IPC status ...
T ... KEY ... NATTCH       SEGSZ CPID ... ISMATTCH     PROJECT
Shared Memory:
m ... 0x1          1 12884901888 3832 ...        1 group.staff

$ zonestat 1 1
Collecting data for first interval...
Interval: 1, Duration: 0:00:01
SUMMARY  Cpus/Online: 24/24   PhysMem: 23.9G  VirtMem: 27.9G
          ---CPU----  --PhysMem-- --VirtMem-- --PhysNet--
     ZONE  USED %PART  USED %USED  USED %USED PBYTE %PUSE
  [total]  0.30 1.27% 14.1G 59.1% 22.0G 78.8%  181K 0.00%
 [system]  0.30 1.27% 8309M 33.8%  9.9G 35.5%     -     -
      ...  0.00 0.00% 6225M 25.3% 12.1G 43.2%   432 0.00%

$ prstat -c -p 3832 1 1
Please wait...
 PID USERNAME  SIZE   RSS ...     
3832 ...        12G 6146M ...

...

$ pmap -x 3832 | head
3832:    ./shm_v04
         Address   Kbytes     RSS ... Locked Mode  Mapped File
0000000000400000        8       8 ...      - r-x-- shm_v04
0000000000411000        8       8 ...      - rw--- shm_v04
0000000000413000      160      68 ...      - rw---  [ heap ]
FFFF80FC80000000 12582912 6291456 ...      - rwxs-  [ dism ... ]
...

Detaching shared memory.
Press <ENTER> to continue...
Success!


vlab-3 $ swap -lh; swap -sh
swapfile             dev    swaplo   blocks     free
/dev/swap
             -         4K     4.0G     3.9G
total: 6.5G allocated + 6.2G reserved = 13G used, 5.9G available

$ ipcs -mA
IPC status ...
T ... KEY ... NATTCH       SEGSZ CPID ... ISMATTCH     PROJECT
Shared Memory:
m ... 0x1          0 12884901888 3832 ...        0 group.staff

vlab-3 $ zonestat 1 1
Collecting data for first interval...
Interval: 1, Duration: 0:00:01
SUMMARY  Cpus/Online: 24/24   PhysMem: 23.9G  VirtMem: 27.9G
          ---CPU----  --PhysMem-- --VirtMem-- --PhysNet--
     ZONE  USED %PART  USED %USED  USED %USED PBYTE %PUSE
  [total]  0.29 1.22% 14.1G 59.1% 22.0G 78.8%   228 0.00%
 [system]  0.29 1.22% 14.1G 58.8%  9.9G 35.5%     -     -
      ...  0.00 0.00% 81.5M 0.33% 12.1G 43.2%   228 0.00%

$ prstat -c -p 3832 1 1
Please wait...
 PID USERNAME  SIZE   RSS ...     
3832 ...      5140K 2180K ...
...

$ pmap -x 3832 | head
3832:    ./shm_v04
         Address Kbytes  RSS ... Locked Mode  Mapped File
0000000000400000
     8    8 ...      - r-x-- shm_v04
0000000000411000      8    8 ...      - rw--- shm_v04
0000000000413000    160   68 ...      - rw---  [ heap ]
FFFF80FFB8F00000   1620 1024 ...      - r-x-- libCstd.so.1
...

Removing shared memory.
Press <ENTER> to continue...
Success!


$ swap -lh; swap -sh
swapfile             dev    swaplo   blocks     free
/dev/swap             -         4K     4.0G     3.9G
total: 500M allocated + 171M reserved = 672M used, 18G available

$ ipcs -mA
IPC status ...
T ... KEY ... NATTCH      SEGSZ CPID ... ISMATTCH     PROJECT
Shared Memory:

$ zonestat 1 1
Collecting data for first interval...
Interval: 1, Duration: 0:00:01
SUMMARY  Cpus/Online: 24/24   PhysMem: 23.9G  VirtMem: 27.9G
          ---CPU----  --PhysMem-- --VirtMem-- --PhysNet--
     ZONE  USED %PART  USED %USED  USED %USED PBYTE %PUSE
  [total]  0.26 1.11% 8385M 34.1% 10.0G 35.9%   228 0.00%
 [system]  0.26 1.11% 8303M 33.8%  9.9G 35.5%     -     -
      ...  0.00 0.00% 81.5M 0.33%  123M 0.43%   228 0.00%

$ prstat -c -p 3832 1 1
Please wait...
 PID USERNAME  SIZE   RSS ...     
3832 ...      5140K 2180K ...
...

Exiting program.
Press <ENTER> to continue...


When Oracle Database fellows argues that "DISM can be dynamically resized depending on the application demand" they induce sysadmins to confusion or error.

As seen above throughout ipcs -mA on all the "output groups" the shared segment size never changes. What may change is the amount of memory the application chooses to lock, contrasting to ISM where the kernel always keep the whole segment locked.

Furthermore, they also believe that "Solaris does not allocate or reserve memory of size SGA_MAX_SIZE at instance startup". Again, for me, this is a misconception of them. I'm convinced that Oracle Database do reserve one or more large DISM segments, but that may not be apparent for a DBA, but the above output shows that Solaris does.

The behavior of ::shmget() is the same for ISM and DISM. The differences start, depending on how the segment is attached to the process. But before that no system resources are actually used, just accounted in the kernel (as a "promise" to the process which called ::shmget()).

Attaching DISM to a process, also just accounts pageable (as seen by pmap -x Mode flag) virtual memory to the process, but not yet any actual resources.

Locking a portion of (or the whole) DISM segment causes adjustments to virtual memory figures (allocated x reserved) because actual resources are allocated. Memory overhead is credited into kernel figures and the process resident size (RSS) also grows.

On the 5th "output group" we see that touching more memory than is locked (as in this sample code), causes even more pages to be allocated. In the example, we touch twice more than is currently locked, just to be more eye catching.

Unlocking DISM, reliefs the accounting of virtual memory but not necessarily frees physical memory (no pageouts) as there may not be memory pressure (as in this example).

And as with ISM, detaching shared memory, just unmaps it from the process, but not from the kernel. To free kernel resources the ::shmctl() must be issued.
 

ISM run sample 3.0

This is a sample run for ISM of the shared memory code sample 3.0:

$ getent user_attr prime    ...::::defaultpriv=basic,proc_lock_memory;...

$ swap -lh; swap -sh
swapfile             dev    swaplo   blocks     free
/dev/swap             -         4K     4.0G     3.9G
total: 496M allocated + 170M reserved = 668M used, 18G available

$ ipcs -mA
IPC status ...
T ... KEY ... NATTCH      SEGSZ CPID ... ISMATTCH     PROJECT
Shared Memory:

$ zonestat 1 1
Collecting data for first interval...
Interval: 1, Duration: 0:00:01
SUMMARY   Cpus/Online: 24/24   PhysMem: 23.9G  VirtMem: 27.9G
          ---CPU----  --PhysMem-- --VirtMem-- --PhysNet--
     ZONE  USED %PART  USED %USED  USED %USED PBYTE %PUSE
  [total]  0.26 1.09% 7719M 31.4% 10.0G 35.8%  540K 0.00%
 [system]  0.26 1.09% 7632M 31.0%  9.9G 35.4%     -     -
      ...  0.00 0.00% 86.9M 0.35%  117M 0.40%  1280 0.00%

Getting shared memory.
Press <ENTER> to continue...
Success!


$ swap -lh; swap -sh
swapfile             dev    swaplo   blocks     free
/dev/swap             -         4K     4.0G     3.9G
total: 496M allocated + 1.2G reserved = 1.7G used, 17G available

$ ipcs -mA
IPC status ...
T ... KEY ... NATTCH      SEGSZ CPID ... ISMATTCH     PROJECT
Shared Memory:
m ... 0x1 ...      0 1073741824 3253 ...        0 group.staff

$ zonestat 1 1
Collecting data for first interval...
Interval: 1, Duration: 0:00:01
SUMMARY  Cpus/Online: 24/24   PhysMem: 23.9G  VirtMem: 27.9G
          ---CPU----  --PhysMem-- --VirtMem-- --PhysNet--
     ZONE  USED %PART  USED %USED  USED %USED PBYTE %PUSE
  [total]  0.25 1.05% 7720M 31.4% 11.0G 39.4%   317 0.00%
 [system]  0.25 1.05% 7633M 31.0%  9.9G 35.4%     -     -
      ...  0.00 0.00% 86.9M 0.35% 1144M 3.99%   317 0.00%

$ prstat -c -p 3253 1 1
Please wait...
   PID USERNAME  SIZE   RSS ... 
  3253 ...      3832K 1720K 
...

Attaching to shared memory.
Press <ENTER> to continue...
Success!


$ swap -lh; swap -sh
swapfile             dev    swaplo   blocks     free
/dev/swap             -         4K     4.0G     3.9G
total: 1.5G allocated + 182M reserved = 1.7G used, 17G available

$ ipcs -mA
IPC status ...
T ... KEY ... NATTCH      SEGSZ CPID ... ISMATTCH     PROJECT
Shared Memory:
m ... 0x1 ...      1 1073741824 3253 ...        1 group.staff

$ zonestat 1 1
Collecting data for first interval...
Interval: 1, Duration: 0:00:01
SUMMARY  Cpus/Online: 24/24   PhysMem: 23.9G  VirtMem: 27.9G
          ---CPU----  --PhysMem-- --VirtMem-- --PhysNet--
     ZONE  USED %PART  USED %USED  USED %USED PBYTE %PUSE
  [total]  0.25 1.07% 8741M 35.5% 11.0G 39.4%  1347 0.00%
 [system]  0.25 1.06% 7631M 31.0%  9.9G 35.4%     -     -
      ...  0.00 0.00% 1109M 4.51% 1148M 4.00%  1347 0.00%

$ prstat -c -p 3253 1 1
Please wait...
   PID USERNAME  SIZE   RSS ...     
  3253 ...      1028M 1026M ...
...

$ pmap -x 3253 | head
3253:    ./shm_v04
 Address  Kbytes     RSS ...  Locked Mode  Mapped File
08050000       8       8 ...       - r-x-- shm_v04
08061000       4       4 ...       - rwx-- shm_v04
08062000     128      44 ...       - rwx--   [ heap ]
80000000 1048576 1048576 ... 1048576 rwxsR   [ ism shmid=... ]
...

Locking shared memory.
Press <ENTER> to continue...
Success!


    not relevant for ISM

Using shared memory.
Press <ENTER> to continue...
Success!


    not relevant for ISM

Unlocking shared memory.
Press <ENTER> to continue...
Success!


    not relevant for ISM

Detaching shared memory.
Press <ENTER> to continue...
Success!


$ swap -lh; swap -sh
swapfile             dev    swaplo   blocks     free
/dev/swap             -         4K     4.0G     3.9G
total: 1.5G allocated + 182M reserved = 1.7G used, 17G available

$ ipcs -mA
IPC status ...
T ... KEY ... NATTCH      SEGSZ CPID ... ISMATTCH     PROJECT
Shared Memory:
m ... 0x1 ...      0 1073741824 3253 ...        0 group.staff

$ zonestat 1 1
Collecting data for first interval...
Interval: 1, Duration: 0:00:01
SUMMARY  Cpus/Online: 24/24   PhysMem: 23.9G  VirtMem: 27.9G
          ---CPU----  --PhysMem-- --VirtMem-- --PhysNet--
     ZONE  USED %PART  USED %USED  USED %USED PBYTE %PUSE
  [total]  0.24 1.03% 8742M 35.5% 11.0G 39.4%   228 0.00%
 [system]  0.24 1.03% 8656M 35.2%  9.9G 35.4%     -     -
      ...  0.00 0.00% 85.9M 0.34% 1143M 3.99%   228 0.00%

$ prstat -c -p 3253 1 1
Please wait...
   PID USERNAME  SIZE   RSS ...     
  3253 ...      3832K 1720K ...
...

$ pmap -x 3253 | head
3253:    ./shm_v04
 Address  Kbytes     RSS ... Locked Mode   Mapped File
08050000       8       8 ...      - r-x--  shm_v04
08061000       4       4 ...      - rwx--  shm_v04
08062000     128      44 ...      - rwx--    [ heap ]
FE380000      24      12 ...      - rwx--    [ anon ]
...

Removing shared memory.
Press <ENTER> to continue...
Success!


$ swap -lh; swap -sh
swapfile             dev    swaplo   blocks     free
/dev/swap             -         4K     4.0G     3.9G
total: 496M allocated + 174M reserved = 668M used, 18G available

$ ipcs -mA
IPC status ...
T ... KEY ... NATTCH      SEGSZ CPID ... ISMATTCH     PROJECT
Shared Memory:

$ zonestat 1 1
Collecting data for first interval...
Interval: 1, Duration: 0:00:01
SUMMARY  Cpus/Online: 24/24   PhysMem: 23.9G  VirtMem: 27.9G
          ---CPU----  --PhysMem-- --VirtMem-- --PhysNet--
     ZONE  USED %PART  USED %USED  USED %USED PBYTE %PUSE
  [total]  0.30 1.25% 7718M 31.4% 10.0G 35.8%  9852 0.00%
 [system]  0.30 1.25% 7632M 31.0%  9.9G 35.4%     -     -
      ...  0.00 0.00% 85.9M 0.34%  120M 0.41%   228 0.00%

$ prstat -c -p 3253 1 1
Please wait...
   PID USERNAME  SIZE   RSS ...     
  3253 ...      3832K 1720K ...
...

Exiting program.
Press <ENTER> to continue...


When Oracle Database fellows argues that "::shmget() requires swap reservation" they induce sysadmins to confusion or error.

As seen above (on the 2nd "output group") what happens is simply virtual memory reservation within the kernel. Note there's no other swap maneuver or switch between disk and physical memory and so on. The process that does the call doesn't even exhibit different figures.

With ISM, physical memory actually gets allocated only when the reserved shared segment is mapped in the calling process via ::shmat(). This is clearly seen in the 3rd "output group" above.

We also see that ::shmdt() doesn't really release any allocated memory as seen in the 4th "output group". The shared memory segment is unmapped from the process but continues to exist within the kernel.

It's only when ::shmctl() is called that memory is actually freed (fifth "output group").