1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
/****************************************************************
* *
* Copyright 2001, 2011 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
* under a license. If you do not know the terms of *
* the license, please stop and do not read further. *
* *
****************************************************************/
#include "mdef.h"
#include "gtm_stdio.h"
#include "gtm_socket.h"
#include "gtm_string.h"
#include <sys/un.h>
#include <errno.h>
#include "gdsroot.h"
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsbt.h"
#include "gdsfhead.h"
#include "filestruct.h"
#include "mutex.h"
#include "eintr_wrappers.h"
#include "is_proc_alive.h"
#include "send_msg.h"
#include "gtmsecshr.h"
#ifdef DEBUG
#include "wbox_test_init.h"
#endif
error_def(ERR_MUTEXERR);
error_def(ERR_TEXT);
error_def(ERR_SYSCALL);
#ifndef MUTEX_MSEM_WAKE
GBLREF int mutex_sock_fd;
GBLREF struct sockaddr_un mutex_wake_this_proc;
GBLREF int mutex_wake_this_proc_len;
GBLREF int mutex_wake_this_proc_prefix_len;
GBLREF uint4 process_id;
void
mutex_wake_proc(sm_int_ptr_t pid, int mutex_wake_instance)
{
/*
* Wakeup process by sending a message over waiting process's socket.
* The waiting process (in select) is woken up on sensing input on its
* socket. The message is not relevant, a character will achieve the
* objective. But, we will send the waking process's pid which might
* be of use for debugging.
*/
unsigned char mutex_wake_this_proc_str[2 * SIZEOF(pid_t) + 1];
mutex_wake_msg_t msg;
int status;
ssize_t sendto_res;
static int sendto_fail_pid;
char sendtomsg[256];
/* Set up the socket structure for sending */
strcpy(mutex_wake_this_proc.sun_path + mutex_wake_this_proc_prefix_len,
(char *)pid2ascx(mutex_wake_this_proc_str, *pid));
msg.pid = process_id;
msg.mutex_wake_instance = mutex_wake_instance;
# ifdef DEBUG
if (gtm_white_box_test_case_enabled
&& (WBTEST_SENDTO_EPERM == gtm_white_box_test_case_number))
{
FPRINTF(stderr, "PATH TO SOCKET IS\n%s\n", mutex_wake_this_proc.sun_path);
LONG_SLEEP(20);
}
# endif
/* We have seen an issue where the sendto() call done below blocked for at least more than a minute. The only reason
* we know of this can happen is if the TCPIP buffer on the receiving end of the pipe is already full. But as long as
* the receiving side is waiting for this wakeup message, it should be in a loop clearing the incoming messages thereby
* avoiding this situation. But in reality, we have seen the receiving side not waiting for the wakeup signal at all
* but instead doing something totally different effectively causing a deadlock. One approach to fix this issue is to
* open the mutex socket with the O_NONBLOCK parameter that way the sendto() done below would be a non-blocking send
* but that introduces issues in the mutex logic as it then needs to handle partial messages (this is because a
* non-blocking sendto would send as much bytes as possible before things would block). For now, the only platform
* that use this wakeup scheme is Linux and that is almost transitioning to using memory-semaphores. The blocking
* sendto() issue is therefore not considered critical at this moment. This might need to be revisited in case this
* code starts to get used again. -- nars - 2008/01/15. */
SENDTO_SOCK(mutex_sock_fd, (char *)&msg, SIZEOF(msg), 0, (struct sockaddr *)&mutex_wake_this_proc,
mutex_wake_this_proc_len, sendto_res);
if (0 > sendto_res)
{ /* Sending wakeup to the mutex socket file of the waiting pid can fail if the process terminated (and hence deleted
* its mutex socket file) while waiting for crit. Except for that case, signal an error in case wakeup send fails.
*/
status = errno;
assert(0 != *pid);
/* if the other process could not be woken up with SENDTO_SOCK due to permissions issue,
* try continue_proc() before erroring out */
if (EACCES == status)
continue_proc(*pid);
# ifdef DEBUG
if (gtm_white_box_test_case_enabled
&& (WBTEST_SENDTO_EPERM == gtm_white_box_test_case_number))
{
FPRINTF(stderr, "CALLED CONTINUE_PROC() ON THE OTHER PROCESS\n");
LONG_SLEEP(20);
}
# endif
/* check if the process is still hung; if so, signal an error */
if ((sendto_fail_pid == *pid) && is_proc_alive(*pid, 0))
{
SNPRINTF(sendtomsg, ARRAYSIZE(sendtomsg), "sendto() to pid [%d]", *pid);
send_msg(VARLSTCNT(10) ERR_MUTEXERR, 0, ERR_SYSCALL, 5, LEN_AND_STR(sendtomsg), CALLFROM, status);
assert(FALSE);
}
sendto_fail_pid = *pid;
}
return;
}
#else
void
#ifdef POSIX_MSEM
mutex_wake_proc(sem_t *mutex_wake_msem_ptr)
#else
mutex_wake_proc(msemaphore *mutex_wake_msem_ptr)
#endif
{
/* Unlock the memsem to wake the proc waiting on it */
int rc;
/*
* CAUTION : man pages on beowulf and hrothgar do not
* mention anything about msem_unlock being interrupted.
* It is being assumed here that msem_unlock, if interrupted
* returns -1 and sets errno to EINTR. If the behavior is
* undefined when interrupted, processes waiting to be woken
* up may hang, and WE ARE TOAST!!!
*/
/*
* Additonal note: this was converted to an EINTR wrapper macro.
*/
do
{
rc = MSEM_UNLOCK(mutex_wake_msem_ptr);
} while (-1 == rc && EINTR == errno);
if (0 > rc)
{
assert(FALSE);
rts_error(VARLSTCNT(7) ERR_MUTEXERR, 0, ERR_TEXT, 2,
RTS_ERROR_TEXT("Error with msem_unlock()/sem_post()"), errno);
}
return;
}
#endif
|