blob: 15a55b8eb50515cbfed5c645dd23c91c1fbe520d [file] [log] [blame]
///////////////////////////////////////////////////////////////////////////////
//
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
//
///////////////////////////////////////////////////////////////////////////////
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "mpi.h"
#include "intprocess.h"
#include "monlogging.h"
#include "montrace.h"
CIntProcess::CMap CIntProcess::Map;
sem_t *CIntProcess::Sem = NULL;
char CIntProcess::SemName[100];
CIntProcess::CIntProcess()
{
}
CIntProcess::~CIntProcess()
{
if (Sem != NULL)
{
sem_close(Sem);
sem_unlink(SemName);
}
}
// called on signal
bool CIntProcess::handle_signal(pid_t pid, int status)
{
const char method_name[] = "CIntProcess::handle_signal";
TRACE_ENTRY;
status = status; // touch
Ctx *ctx = CIntProcess::get_ctx(pid);
if (ctx != NULL)
{
if (trace_settings & (TRACE_SIG_HANDLER))
trace_nolock_printf("%s@%d - internal-process exit-callback cb=%p, cb-ctx=%p, cb-pid=%d, pid=%d.\n",
method_name, __LINE__, ctx->exit_cb, ctx->exit_cb_ctx, ctx->exit_cb_pid, pid);
ctx->exit_cb(ctx->exit_cb_ctx, ctx->exit_cb_pid, status);
CIntProcess::remove_ctx(pid);
}
TRACE_EXIT;
return (ctx != NULL);
}
int CIntProcess::create(const char *filename,
char *const argv[],
Exit_Cb exit_cb,
int exit_cb_pid,
void *exit_cb_ctx,
pid_t *pid)
{
int err;
pid_t lpid;
int rc = MPI_SUCCESS;
int sem_rc;
const char method_name[] = "CIntProcess::create";
TRACE_ENTRY;
if (Sem == NULL)
{
// named semaphore is easier than using shared memory
sprintf(SemName, "/monitor.sem3.%s", getenv("USER"));
Sem = sem_open(SemName, O_CREAT, 0644, 0);
if (Sem == SEM_FAILED)
{
char la_buf[MON_STRING_BUF_SIZE];
sprintf(la_buf, "[CIntProcess::create], Can't open semaphore %s!\n",
SemName);
mon_log_write(MON_INTPROCESS_1, SQ_LOG_ERR, la_buf);
rc = MPI_ERR_SPAWN;
Sem = NULL;
}
}
if (rc == MPI_SUCCESS)
{
lpid = fork();
if (pid != NULL)
*pid = lpid;
if (lpid == -1)
{
rc = MPI_ERR_SPAWN;
char la_buf[MON_STRING_BUF_SIZE];
sprintf(la_buf, "[CIntProcess::create], Can't fork errno=%d(%s)!\n",
errno, strerror(errno));
mon_log_write(MON_INTPROCESS_2, SQ_LOG_ERR, la_buf);
}
else if (lpid > 0)
{
// parent
Ctx *ctx = new Ctx();
ctx->intprocess = this;
ctx->exit_cb = exit_cb;
ctx->exit_cb_pid = exit_cb_pid;
ctx->exit_cb_ctx = exit_cb_ctx;
Map.lock();
Map.insert(lpid, ctx);
Map.unlock();
if (trace_settings & (TRACE_PROCESS))
trace_printf("%s@%d - Monitor created internal-process pid=%d.\n",
method_name, __LINE__, lpid);
if (sem_post(Sem) == -1)
{
char la_buf[MON_STRING_BUF_SIZE];
sprintf(la_buf, "[CIntProcess::create], Parent can't post semaphore, errno=%d(%s)!\n",
errno, strerror(errno));
mon_log_write(MON_INTPROCESS_3, SQ_LOG_ERR, la_buf);
}
if (trace_settings & (TRACE_SYNC | TRACE_REQUEST | TRACE_PROCESS))
trace_printf("%s@%d - Monitor completed waiting for child to exec.\n",
method_name, __LINE__);
}
else
{
// child
while (((sem_rc = sem_wait(Sem)) == -1) && (errno == EINTR))
continue; // Restart sem_wait if interrupted by sig handler
if (sem_rc == -1)
{
char la_buf[MON_STRING_BUF_SIZE];
sprintf(la_buf, "[CIntProcess::create], Child can't wait semaphore, errno=%d(%s)!\n",
errno, strerror(errno));
mon_log_write(MON_INTPROCESS_4, SQ_LOG_ERR, la_buf);
abort(); // kill child - if can't get sem
}
err = execvp(filename, argv);
if (err == -1)
{
char la_buf[MON_STRING_BUF_SIZE];
sprintf(la_buf, "[CIntProcess::create], Child can't exec filename=%s, errno=%d(%s)!\n",
filename, errno, strerror(errno));
mon_log_write(MON_INTPROCESS_5, SQ_LOG_ERR, la_buf);
}
abort(); // only gets here if execvp fails
}
}
TRACE_EXIT;
return rc;
}
CIntProcess::Ctx *CIntProcess::get_ctx(pid_t pid)
{
Map_Iter_Type iter = Map.find(pid);
if (iter == Map.end())
return NULL;
else
return iter->second;
}
void CIntProcess::print_map()
{
Map.print_map();
}
void CIntProcess::remove_ctx(pid_t pid)
{
Map.lock();
Ctx *ctx = get_ctx(pid);
if (ctx != NULL)
delete ctx;
Map.erase(pid);
Map.unlock();
}
CIntProcess::CMap::CMap()
{
}
CIntProcess::CMap::~CMap()
{
}
CIntProcess::Map_Iter_Type CIntProcess::CMap::end()
{
return Map.end();
}
void CIntProcess::CMap::erase(pid_t pid)
{
Map.erase(pid);
}
CIntProcess::Map_Iter_Type CIntProcess::CMap::find(pid_t pid)
{
return Map.find(pid);
}
void CIntProcess::CMap::insert(pid_t pid, Ctx *ctx)
{
Map.insert(std::make_pair(pid, ctx));
}
void CIntProcess::CMap::lock()
{
Lock.lock();
}
void CIntProcess::CMap::print_map()
{
Map_Iter_Type iter;
for (iter = Map.begin(); iter != Map.end(); iter++)
{
printf("iter.pid=%d, .ctx=%p\n", iter->first, iter->second);
}
}
void CIntProcess::CMap::unlock()
{
Lock.unlock();
}