1999-04-01 09:35:22 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1999-04-01 09:35:22 +04:00
store smbd profiling information in shared memory
Copyright ( C ) Andrew Tridgell 1999
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
2002-09-25 19:19:00 +04:00
# ifdef WITH_PROFILE
2004-12-19 03:31:31 +03:00
# define IPC_PERMS ((S_IRUSR | S_IWUSR) | S_IRGRP | S_IROTH)
2002-09-25 19:19:00 +04:00
# endif /* WITH_PROFILE */
1999-04-01 09:35:22 +04:00
2002-09-25 19:19:00 +04:00
# ifdef WITH_PROFILE
1999-04-01 09:35:22 +04:00
static int shm_id ;
static BOOL read_only ;
2006-05-08 07:20:49 +04:00
# if defined(HAVE_CLOCK_GETTIME)
clockid_t __profile_clock ;
# endif
2002-09-25 19:19:00 +04:00
# endif
1999-04-01 09:35:22 +04:00
2000-10-11 09:31:39 +04:00
struct profile_header * profile_h ;
struct profile_stats * profile_p ;
1999-04-01 09:35:22 +04:00
2000-10-06 22:13:52 +04:00
BOOL do_profile_flag = False ;
2000-10-07 03:01:47 +04:00
BOOL do_profile_times = False ;
2000-10-06 22:13:52 +04:00
2000-10-07 03:01:47 +04:00
/****************************************************************************
receive a set profile level message
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-12-25 12:49:10 +03:00
void profile_message ( int msg_type , struct process_id src , void * buf , size_t len )
2000-10-07 03:01:47 +04:00
{
int level ;
memcpy ( & level , buf , sizeof ( int ) ) ;
2002-09-25 19:19:00 +04:00
# ifdef WITH_PROFILE
2000-10-07 03:01:47 +04:00
switch ( level ) {
2000-10-11 09:31:39 +04:00
case 0 : /* turn off profiling */
2000-10-07 03:01:47 +04:00
do_profile_flag = False ;
do_profile_times = False ;
2005-12-25 12:49:10 +03:00
DEBUG ( 1 , ( " INFO: Profiling turned OFF from pid %d \n " ,
2005-12-25 13:06:05 +03:00
( int ) procid_to_pid ( & src ) ) ) ;
2000-10-07 03:01:47 +04:00
break ;
2000-10-11 09:31:39 +04:00
case 1 : /* turn on counter profiling only */
2000-10-07 03:01:47 +04:00
do_profile_flag = True ;
do_profile_times = False ;
2005-12-25 12:49:10 +03:00
DEBUG ( 1 , ( " INFO: Profiling counts turned ON from pid %d \n " ,
2005-12-25 13:06:05 +03:00
( int ) procid_to_pid ( & src ) ) ) ;
2000-10-07 03:01:47 +04:00
break ;
2000-10-11 09:31:39 +04:00
case 2 : /* turn on complete profiling */
2000-10-07 03:01:47 +04:00
do_profile_flag = True ;
do_profile_times = True ;
2005-12-25 12:49:10 +03:00
DEBUG ( 1 , ( " INFO: Full profiling turned ON from pid %d \n " ,
2005-12-25 13:06:05 +03:00
( int ) procid_to_pid ( & src ) ) ) ;
2000-10-07 03:01:47 +04:00
break ;
2000-10-11 09:31:39 +04:00
case 3 : /* reset profile values */
memset ( ( char * ) profile_p , 0 , sizeof ( * profile_p ) ) ;
2005-12-25 12:49:10 +03:00
DEBUG ( 1 , ( " INFO: Profiling values cleared from pid %d \n " ,
2005-12-25 13:06:05 +03:00
( int ) procid_to_pid ( & src ) ) ) ;
2000-10-11 09:31:39 +04:00
break ;
2000-10-07 03:01:47 +04:00
}
2002-09-25 19:19:00 +04:00
# else /* WITH_PROFILE */
DEBUG ( 1 , ( " INFO: Profiling support unavailable in this build. \n " ) ) ;
# endif /* WITH_PROFILE */
2000-10-07 03:01:47 +04:00
}
2000-11-11 03:33:33 +03:00
/****************************************************************************
receive a request profile level message
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-09-30 21:13:37 +04:00
void reqprofile_message ( int msg_type , struct process_id src ,
void * buf , size_t len )
2000-11-11 03:33:33 +03:00
{
int level ;
# ifdef WITH_PROFILE
level = 1 + ( do_profile_flag ? 2 : 0 ) + ( do_profile_times ? 4 : 0 ) ;
# else
level = 0 ;
# endif
2005-09-30 21:13:37 +04:00
DEBUG ( 1 , ( " INFO: Received REQ_PROFILELEVEL message from PID %u \n " ,
( unsigned int ) procid_to_pid ( & src ) ) ) ;
2000-11-17 00:38:24 +03:00
message_send_pid ( src , MSG_PROFILELEVEL , & level , sizeof ( int ) , True ) ;
2000-11-11 03:33:33 +03:00
}
1999-04-01 09:35:22 +04:00
/*******************************************************************
open the profiling shared memory area
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
# ifdef WITH_PROFILE
1999-04-01 09:35:22 +04:00
BOOL profile_setup ( BOOL rdonly )
{
struct shmid_ds shm_ds ;
read_only = rdonly ;
2006-05-08 07:20:49 +04:00
# if defined(HAVE_CLOCK_GETTIME)
if ( this_is_smp ( ) ) {
/* This is faster that gettimeofday, but not fast enough to
* leave it enabled in production .
*/
__profile_clock = CLOCK_MONOTONIC ;
} else {
/* CLOCK_PROCESS_CPUTIME_ID is sufficiently fast that the
* always profiling times is plausible . Unfortunately it is
* only accurate if we can guarantee we will not be scheduled
* onto a different CPU between samples . Until there is some
* way to set processor affinity , we can only use this on
* uniprocessors .
*/
__profile_clock = CLOCK_PROCESS_CPUTIME_ID ;
}
# endif
1999-04-01 09:35:22 +04:00
again :
/* try to use an existing key */
1999-12-13 16:27:58 +03:00
shm_id = shmget ( PROF_SHMEM_KEY , 0 , 0 ) ;
1999-04-01 09:35:22 +04:00
/* if that failed then create one. There is a race condition here
if we are running from inetd . Bad luck . */
if ( shm_id = = - 1 ) {
if ( read_only ) return False ;
2000-10-11 09:31:39 +04:00
shm_id = shmget ( PROF_SHMEM_KEY , sizeof ( * profile_h ) ,
1999-04-01 09:35:22 +04:00
IPC_CREAT | IPC_EXCL | IPC_PERMS ) ;
}
if ( shm_id = = - 1 ) {
DEBUG ( 0 , ( " Can't create or use IPC area. Error was %s \n " ,
strerror ( errno ) ) ) ;
return False ;
}
2000-10-11 09:31:39 +04:00
profile_h = ( struct profile_header * ) shmat ( shm_id , 0 ,
1999-04-01 09:35:22 +04:00
read_only ? SHM_RDONLY : 0 ) ;
if ( ( long ) profile_p = = - 1 ) {
DEBUG ( 0 , ( " Can't attach to IPC area. Error was %s \n " ,
strerror ( errno ) ) ) ;
return False ;
}
/* find out who created this memory area */
if ( shmctl ( shm_id , IPC_STAT , & shm_ds ) ! = 0 ) {
DEBUG ( 0 , ( " ERROR shmctl : can't IPC_STAT. Error was %s \n " ,
strerror ( errno ) ) ) ;
return False ;
}
2001-09-15 06:10:22 +04:00
if ( shm_ds . shm_perm . cuid ! = sec_initial_uid ( ) | | shm_ds . shm_perm . cgid ! = sec_initial_gid ( ) ) {
DEBUG ( 0 , ( " ERROR: we did not create the shmem (owned by another user) \n " ) ) ;
1999-04-01 09:35:22 +04:00
return False ;
}
2000-10-11 09:31:39 +04:00
if ( shm_ds . shm_segsz ! = sizeof ( * profile_h ) ) {
1999-04-01 09:35:22 +04:00
DEBUG ( 0 , ( " WARNING: profile size is %d (expected %d). Deleting \n " ,
2000-10-11 09:31:39 +04:00
( int ) shm_ds . shm_segsz , sizeof ( * profile_h ) ) ) ;
1999-04-01 09:35:22 +04:00
if ( shmctl ( shm_id , IPC_RMID , & shm_ds ) = = 0 ) {
goto again ;
} else {
return False ;
}
}
if ( ! read_only & & ( shm_ds . shm_nattch = = 1 ) ) {
2000-10-11 09:31:39 +04:00
memset ( ( char * ) profile_h , 0 , sizeof ( * profile_h ) ) ;
profile_h - > prof_shm_magic = PROF_SHM_MAGIC ;
profile_h - > prof_shm_version = PROF_SHM_VERSION ;
1999-04-01 09:35:22 +04:00
DEBUG ( 3 , ( " Initialised profile area \n " ) ) ;
}
2000-10-11 09:31:39 +04:00
profile_p = & profile_h - > stats ;
2000-10-07 03:01:47 +04:00
message_register ( MSG_PROFILE , profile_message ) ;
2000-11-11 03:33:33 +03:00
message_register ( MSG_REQ_PROFILELEVEL , reqprofile_message ) ;
1999-04-01 09:35:22 +04:00
return True ;
}
2002-09-25 19:19:00 +04:00
# endif /* WITH_PROFILE */