// Copyright (C) 2005 David Sugar, Tycho Softworks.
//
// 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// As a special exception, you may use this file as part of a free software
// library without restriction. Specifically, if other files instantiate
// templates or use macros or inline functions from this file, or you compile
// this file and link it with other files to produce an executable, this
// file does not by itself cause the resulting executable to be covered by
// the GNU General Public License. This exception does not however
// invalidate any other reasons why the executable file might be covered by
// the GNU General Public License.
//
// This exception applies only to the code released under the name GNU
// ccScript. If you copy code from other releases into a copy of GNU
// ccScript, as the General Public License permits, the exception does
// not apply to the code that you add in this way. To avoid misleading
// anyone as to the status of such modified files, you must delete
// this exception notice from them.
//
// If you write modifications of your own for GNU ccScript, it is your choice
// whether to permit this exception to apply to your modifications.
// If you do not wish that, delete this exception notice.
//
#include "script3.h"
#include <cc++/slog.h>
#include <cstdio>
namespace ccscript3Extension {
using namespace std;
using namespace ost;
class LockerChecks : public ScriptChecks
{
public:
const char *chkAquire(Line *line, ScriptImage *img);
const char *chkRelease(Line *line, ScriptImage *img);
};
class LockerMethods : public ScriptMethods
{
public:
bool scrAquire(void);
bool scrRelease(void);
};
class LockerBinder : public ScriptBinder, public Assoc, public SharedMemPager
{
private:
unsigned count;
void detach(ScriptInterp *interp);
void *getMemory(size_t size);
public:
void release(const char *id, void *v);
bool aquire(const char *id, void *v);
LockerBinder();
static LockerBinder locker;
};
static Script::Define runtime[] = {
{"aquire", false, (Script::Method)&LockerMethods::scrAquire,
(Script::Check)&LockerChecks::chkAquire},
{"release", false, (Script::Method)&LockerMethods::scrRelease,
(Script::Check)&LockerChecks::chkRelease},
{NULL, false, NULL, NULL}};
LockerBinder LockerBinder::locker;
LockerBinder::LockerBinder() :
ScriptBinder("locker"), Assoc(), SharedMemPager(1024)
{
count = 0;
bind(runtime);
slog.debug("locking service loaded");
}
void *LockerBinder::getMemory(size_t size)
{
return alloc(size);
}
bool LockerBinder::aquire(const char *id, void *v)
{
bool rtn = false;
void *dp;
enterMutex();
dp = getPointer(id);
if(!dp)
{
setPointer(id, v);
++count;
rtn = true;
}
else if(dp == v)
rtn = true;
leaveMutex();
return rtn;
}
void LockerBinder::release(const char *id, void *v)
{
void *dp;
enterMutex();
dp = getPointer(id);
if(dp && dp == v)
{
setPointer(id, NULL);
--count;
}
if(!count)
{
slog.debug("locker purging...");
Assoc::clear();
SharedMemPager::purge();
}
leaveMutex();
}
void LockerBinder::detach(ScriptInterp *interp)
{
Symbol *list[65];
unsigned count = interp->gathertype(list, 64, "aquired", symCONST);
unsigned idx = 0;
Symbol *sym;
char name[65];
while(idx < count)
{
sym = list[idx++];
if(!sym->data[0])
continue;
snprintf(name, sizeof(name), "%s.%s",
sym->id + 8, sym->data);
LockerBinder::locker.release(name, interp);
sym->data[0] = 0;
}
}
bool LockerMethods::scrAquire(void)
{
const char *tag = getMember();
char name[65];
char var[65];
Symbol *sym;
const char *id = getOption(NULL);
Name *scr = getName();
char *ep;
if(!tag)
{
setString(var, sizeof(var), scr->name);
ep = strrchr(var, ':');
if(ep)
*ep = 0;
tag = var;
}
if(!id || !*id)
{
error("invalid-lock");
return true;
}
snprintf(name, sizeof(name), "aquired.%s", tag);
sym = mapSymbol(name, 32);
if(sym->type == symINITIAL)
sym->type = symCONST;
if(!sym || sym->type != symCONST)
{
error("lock-failed");
return true;
}
if(sym->data[0] && !stricmp(sym->data, id))
goto locked;
if(sym->data[0])
{
snprintf(name, sizeof(name), "%s.%s", tag, sym->data);
LockerBinder::locker.release(name, this);
sym->data[0] = 0;
}
snprintf(name, sizeof(name), "%s.%s", tag, id);
if(!LockerBinder::locker.aquire(name, this))
{
error("lock-used");
return false;
}
locked:
setString(sym->data, sym->size + 1, id);
if(frame[stack].index < frame[stack].line->argc)
intGoto();
advance();
return true;
}
bool LockerMethods::scrRelease(void)
{
const char *tag = getMember();
char name[65];
char var[65];
Symbol *sym;
char *ep;
Name *scr = getName();
if(!tag)
{
setString(var, sizeof(var), scr->name);
ep = strchr(var, ':');
if(ep)
*ep = 0;
tag = var;
}
snprintf(name, sizeof(name), "aquired.%s", tag);
sym = mapSymbol(name, 0);
if(!sym || sym->type != symCONST || !sym->data[0])
{
error("no-lock");
return true;
}
snprintf(name, sizeof(name), "%s.%s", tag, sym->data);
sym->data[0] = 0;
LockerBinder::locker.release(name, this);
advance();
return true;
}
const char *LockerChecks::chkRelease(Line *line, ScriptImage *img)
{
if(line->argc)
return "release has no options or arguments";
return NULL;
}
const char *LockerChecks::chkAquire(Line *line, ScriptImage *img)
{
unsigned idx = 0;
const char *cp;
if(hasKeywords(line))
return "aquire has no keywords";
if(!getOption(line, &idx))
return "aquire needs id argument";
cp = getOption(line, &idx);
if(!cp)
return NULL;
if(getOption(line, &idx))
return "only one label for aquire";
return NULL;
}
};
syntax highlighted by Code2HTML, v. 0.9.1