Page MenuHomeClusterLabs Projects

score.c
No OneTemporary

/**
Copyright Red Hat, Inc. 2006
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, 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; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
MA 02139, USA.
Author: Lon Hohberger <lhh at redhat.com>
*/
/**
@file Quorum daemon scoring functions + thread.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <pthread.h>
#include <string.h>
#include <ccs.h>
#include <clulog.h>
#include "score.h"
static pthread_mutex_t sc_lock = PTHREAD_MUTEX_INITIALIZER;
static int _score = 0, _maxscore = 0, _score_thread_running = 0;
static pthread_t score_thread = (pthread_t)0;
struct h_arg {
struct h_data *h;
int count;
};
/*
XXX Messy, but works for now...
*/
void
nullify(void)
{
int fd[3];
close(0);
close(1);
close(2);
fd[0] = open("/dev/null", O_RDONLY);
if (fd[0] != 0)
dup2(fd[0], 0);
fd[1] = open("/dev/null", O_WRONLY);
if (fd[1] != 1)
dup2(fd[1], 1);
fd[2] = open("/dev/null", O_WRONLY);
if (fd[2] != 2)
dup2(fd[2], 2);
}
/**
Spin off a user-defined heuristic
*/
static int
fork_heuristic(struct h_data *h)
{
int pid;
char *argv[4];
time_t now;
if (h->childpid) {
errno = EINPROGRESS;
return -1;
}
now = time(NULL);
if (now < h->nextrun)
return 0;
h->nextrun = now + h->interval;
pid = fork();
if (pid < 0)
return -1;
if (pid) {
h->childpid = pid;
return 0;
}
argv[0] = "/bin/sh";
argv[1] = "-c";
argv[2] = h->program;
argv[3] = NULL;
nullify();
execv("/bin/sh", argv);
printf("Execv failed\n");
return 0;
}
/**
Total our current score
*/
static void
total_score(struct h_data *h, int max, int *score, int *maxscore)
{
int x;
*score = 0;
*maxscore = 0;
for (x = 0; x < max; x++) {
*maxscore += h[x].score;
if (h[x].available)
*score += h[x].score;
}
}
/**
Check for response from a user-defined heuristic / script
*/
static int
check_heuristic(struct h_data *h, int block)
{
int ret;
int status;
if (h->childpid == 0)
return 0;
ret = waitpid(h->childpid, &status, block?0:WNOHANG);
if (!block && ret == 0)
return 0;
h->childpid = 0;
h->available = 0;
if (ret < 0 && errno == ECHILD)
return -1;
if (!WIFEXITED(status))
return 0;
if (WEXITSTATUS(status) != 0)
return 0;
h->available = 1;
return 0;
}
/**
Kick off all available heuristics
*/
static int
fork_heuristics(struct h_data *h, int max)
{
int x;
for (x = 0; x < max; x++)
fork_heuristic(&h[x]);
return 0;
}
/**
Check all available heuristics
*/
static int
check_heuristics(struct h_data *h, int max, int block)
{
int x;
for (x = 0; x < max; x++)
check_heuristic(&h[x], block);
return 0;
}
/**
Read configuration data from CCS into the array provided
*/
int
configure_heuristics(int ccsfd, struct h_data *h, int max)
{
int x = 0;
char *val;
char query[128];
if (!h || !max)
return -1;
do {
h[x].program = NULL;
h[x].available = 0;
h[x].interval = 2;
h[x].score = 1;
h[x].childpid = 0;
h[x].nextrun = 0;
/* Get program */
snprintf(query, sizeof(query),
"/cluster/quorumd/heuristic[%d]/@program", x+1);
if (ccs_get(ccsfd, query, &val) != 0)
/* No more */
break;
h[x].program = val;
/* Get score */
snprintf(query, sizeof(query),
"/cluster/quorumd/heuristic[%d]/@score", x+1);
if (ccs_get(ccsfd, query, &val) == 0) {
h[x].score = atoi(val);
free(val);
if (h[x].score <= 0)
h[x].score = 1;
}
/* Get query interval */
snprintf(query, sizeof(query),
"/cluster/quorumd/heuristic[%d]/@interval", x+1);
if (ccs_get(ccsfd, query, &val) == 0) {
h[x].interval = atoi(val);
free(val);
if (h[x].interval <= 0)
h[x].interval = 2;
}
clulog(LOG_DEBUG, "Heuristic: '%s' score=%d interval=%d\n",
h[x].program, h[x].score, h[x].interval);
} while (++x < max);
clulog(LOG_DEBUG, "%d heuristics loaded\n", x);
return x;
}
/**
Return the current score + maxscore to the caller
*/
int
get_my_score(int *score, int *maxscore)
{
pthread_mutex_lock(&sc_lock);
*score = _score;
*maxscore = _maxscore;
pthread_mutex_unlock(&sc_lock);
return 0;
}
/**
Loop for the scoring thread.
*/
void *
score_thread_main(void *arg)
{
struct h_arg *args = (struct h_arg *)arg;
int score, maxscore;
while (_score_thread_running) {
fork_heuristics(args->h, args->count);
check_heuristics(args->h, args->count, 0);
total_score(args->h, args->count, &score, &maxscore);
pthread_mutex_lock(&sc_lock);
_score = score;
_maxscore = maxscore;
pthread_mutex_unlock(&sc_lock);
if (_score_thread_running)
sleep(1);
}
free(args->h);
free(args);
printf("Score thread going away\n");
return (NULL);
}
/**
Stop the score thread for shutdown / reconfiguration
*/
int
stop_score_thread(void)
{
void *ret;
if (!_score_thread_running)
return 0;
_score_thread_running = 0;
pthread_join(score_thread, &ret);
return 0;
}
/**
Start the score thread. h is copied into an argument which is
passed in as the arg parameter in the score thread, so it is safe
to pass in h if it was allocated on the stack.
*/
int
start_score_thread(struct h_data *h, int count)
{
pthread_attr_t attrs;
struct h_arg *args;
if (!h || !count)
return -1;
args = malloc(sizeof(struct h_arg));
if (!args)
return -1;
args->h = malloc(sizeof(struct h_data) * count);
if (!args->h) {
free(args);
return -1;
}
memcpy(args->h, h, (sizeof(struct h_data) * count));
args->count = count;
_score_thread_running = 1;
pthread_attr_init(&attrs);
pthread_attr_setinheritsched(&attrs, PTHREAD_INHERIT_SCHED);
pthread_create(&score_thread, &attrs, score_thread_main, args);
pthread_attr_destroy(&attrs);
if (score_thread)
return 0;
_score_thread_running = 0;
return -1;
}
#if 0
int
main(int argc, char **argv)
{
struct h_data h[10];
int max = 0, score, maxscore, ccsfd;
ccsfd = ccs_force_connect("test", 1);
if (ccsfd < 0)
return -1;
max = configure_heuristics(ccsfd, h, 10);
ccs_disconnect(ccsfd);
start_score_thread(h, max);
max = 0;
while (max < 10) {
get_my_score(&score,&maxscore);
printf("current %d/%d\n", score, maxscore);
sleep(1);
++max;
}
stop_score_thread();
get_my_score(&score,&maxscore);
printf("final! %d/%d\n", score, maxscore);
return 0;
}
#endif

File Metadata

Mime Type
text/x-c
Expires
Wed, Feb 26, 7:20 PM (22 m ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1465684
Default Alt Text
score.c (6 KB)

Event Timeline