Make the server suspend the core around calls unless disabled.

I expect the majority of methods will have to suspend the core
first thing anyway, so this will reduce typing and bugs.

Also get rid of the "me->" ugliness by splitting threadFn.
develop
Alexander Gavrilov 2012-03-18 11:04:15 +04:00
parent 293eb53677
commit b9ecd03fe2
6 changed files with 71 additions and 34 deletions

@ -198,6 +198,14 @@ void ServerConnection::connection_ostream::flush_proxy()
void ServerConnection::threadFn(void *arg) void ServerConnection::threadFn(void *arg)
{ {
ServerConnection *me = (ServerConnection*)arg; ServerConnection *me = (ServerConnection*)arg;
me->threadFn();
delete me;
}
void ServerConnection::threadFn()
{
color_ostream_proxy out(Core::getInstance().getConsole()); color_ostream_proxy out(Core::getInstance().getConsole());
/* Handshake */ /* Handshake */
@ -205,10 +213,9 @@ void ServerConnection::threadFn(void *arg)
{ {
RPCHandshakeHeader header; RPCHandshakeHeader header;
if (!readFullBuffer(me->socket, &header, sizeof(header))) if (!readFullBuffer(socket, &header, sizeof(header)))
{ {
out << "In RPC server: could not read handshake header." << endl; out << "In RPC server: could not read handshake header." << endl;
delete me;
return; return;
} }
@ -216,17 +223,15 @@ void ServerConnection::threadFn(void *arg)
header.version != 1) header.version != 1)
{ {
out << "In RPC server: invalid handshake header." << endl; out << "In RPC server: invalid handshake header." << endl;
delete me;
return; return;
} }
memcpy(header.magic, RPCHandshakeHeader::RESPONSE_MAGIC, sizeof(header.magic)); memcpy(header.magic, RPCHandshakeHeader::RESPONSE_MAGIC, sizeof(header.magic));
header.version = 1; header.version = 1;
if (me->socket->Send((uint8*)&header, sizeof(header)) != sizeof(header)) if (socket->Send((uint8*)&header, sizeof(header)) != sizeof(header))
{ {
out << "In RPC server: could not send handshake response." << endl; out << "In RPC server: could not send handshake response." << endl;
delete me;
return; return;
} }
} }
@ -235,11 +240,11 @@ void ServerConnection::threadFn(void *arg)
std::cerr << "Client connection established." << endl; std::cerr << "Client connection established." << endl;
while (!me->in_error) { while (!in_error) {
// Read the message // Read the message
RPCMessageHeader header; RPCMessageHeader header;
if (!readFullBuffer(me->socket, &header, sizeof(header))) if (!readFullBuffer(socket, &header, sizeof(header)))
{ {
out.printerr("In RPC server: I/O error in receive header.\n"); out.printerr("In RPC server: I/O error in receive header.\n");
break; break;
@ -256,7 +261,7 @@ void ServerConnection::threadFn(void *arg)
std::auto_ptr<uint8_t> buf(new uint8_t[header.size]); std::auto_ptr<uint8_t> buf(new uint8_t[header.size]);
if (!readFullBuffer(me->socket, buf.get(), header.size)) if (!readFullBuffer(socket, buf.get(), header.size))
{ {
out.printerr("In RPC server: I/O error in receive %d bytes of data.\n", header.size); out.printerr("In RPC server: I/O error in receive %d bytes of data.\n", header.size);
break; break;
@ -267,31 +272,40 @@ void ServerConnection::threadFn(void *arg)
// Find and call the function // Find and call the function
int in_size = header.size; int in_size = header.size;
ServerFunctionBase *fn = vector_get(me->functions, header.id); ServerFunctionBase *fn = vector_get(functions, header.id);
MessageLite *reply = NULL; MessageLite *reply = NULL;
command_result res = CR_FAILURE; command_result res = CR_FAILURE;
if (!fn) if (!fn)
{ {
me->stream.printerr("RPC call of invalid id %d\n", header.id); stream.printerr("RPC call of invalid id %d\n", header.id);
} }
else else
{ {
if (!fn->in()->ParseFromArray(buf.get(), header.size)) if (!fn->in()->ParseFromArray(buf.get(), header.size))
{ {
me->stream.printerr("In call to %s: could not decode input args.\n", fn->name); stream.printerr("In call to %s: could not decode input args.\n", fn->name);
} }
else else
{ {
buf.reset(); buf.reset();
reply = fn->out(); reply = fn->out();
res = fn->execute(me->stream);
if (fn->flags & SF_DONT_SUSPEND)
{
res = fn->execute(stream);
}
else
{
CoreSuspender suspend;
res = fn->execute(stream);
}
} }
} }
// Flush all text output // Flush all text output
if (me->in_error) if (in_error)
break; break;
//out.print("Answer %d:%d\n", res, reply); //out.print("Answer %d:%d\n", res, reply);
@ -301,16 +315,16 @@ void ServerConnection::threadFn(void *arg)
if (out_size > RPCMessageHeader::MAX_MESSAGE_SIZE) if (out_size > RPCMessageHeader::MAX_MESSAGE_SIZE)
{ {
me->stream.printerr("In call to %s: reply too large: %d.\n", stream.printerr("In call to %s: reply too large: %d.\n",
(fn ? fn->name : "UNKNOWN"), out_size); (fn ? fn->name : "UNKNOWN"), out_size);
res = CR_LINK_FAILURE; res = CR_LINK_FAILURE;
} }
me->stream.flush(); stream.flush();
if (res == CR_OK && reply) if (res == CR_OK && reply)
{ {
if (!sendRemoteMessage(me->socket, RPC_REPLY_RESULT, reply, true)) if (!sendRemoteMessage(socket, RPC_REPLY_RESULT, reply, true))
{ {
out.printerr("In RPC server: I/O error in send result.\n"); out.printerr("In RPC server: I/O error in send result.\n");
break; break;
@ -321,7 +335,7 @@ void ServerConnection::threadFn(void *arg)
header.id = RPC_REPLY_FAIL; header.id = RPC_REPLY_FAIL;
header.size = res; header.size = res;
if (me->socket->Send((uint8_t*)&header, sizeof(header)) != sizeof(header)) if (socket->Send((uint8_t*)&header, sizeof(header)) != sizeof(header))
{ {
out.printerr("In RPC server: I/O error in send failure code.\n"); out.printerr("In RPC server: I/O error in send failure code.\n");
break; break;
@ -337,8 +351,6 @@ void ServerConnection::threadFn(void *arg)
} }
std::cerr << "Shutting down client connection." << endl; std::cerr << "Shutting down client connection." << endl;
delete me;
} }
ServerMain::ServerMain() ServerMain::ServerMain()

@ -217,6 +217,7 @@ void DFHack::describeName(NameInfo *info, df::language_name *name)
std::string lname = Translation::TranslateName(name, false, true); std::string lname = Translation::TranslateName(name, false, true);
if (!lname.empty()) if (!lname.empty())
info->set_last_name(lname); info->set_last_name(lname);
lname = Translation::TranslateName(name, true, true); lname = Translation::TranslateName(name, true, true);
if (!lname.empty()) if (!lname.empty())
info->set_english_name(lname); info->set_english_name(lname);
@ -276,13 +277,17 @@ static command_result ListEnums(color_ostream &stream,
{ {
#define ENUM(name) describe_enum<df::name>(out->mutable_##name()); #define ENUM(name) describe_enum<df::name>(out->mutable_##name());
#define BITFIELD(name) describe_bitfield<df::name>(out->mutable_##name()); #define BITFIELD(name) describe_bitfield<df::name>(out->mutable_##name());
ENUM(material_flags); ENUM(material_flags);
ENUM(inorganic_flags); ENUM(inorganic_flags);
BITFIELD(unit_flags1); BITFIELD(unit_flags1);
BITFIELD(unit_flags2); BITFIELD(unit_flags2);
BITFIELD(unit_flags3); BITFIELD(unit_flags3);
ENUM(unit_labor); ENUM(unit_labor);
ENUM(job_skill); ENUM(job_skill);
#undef ENUM #undef ENUM
#undef BITFIELD #undef BITFIELD
} }
@ -297,8 +302,6 @@ static void listMaterial(ListMaterialsOut *out, int type, int index, const Basic
static command_result ListMaterials(color_ostream &stream, static command_result ListMaterials(color_ostream &stream,
const ListMaterialsIn *in, ListMaterialsOut *out) const ListMaterialsIn *in, ListMaterialsOut *out)
{ {
CoreSuspender suspend;
auto mask = in->has_mask() ? &in->mask() : NULL; auto mask = in->has_mask() ? &in->mask() : NULL;
for (int i = 0; i < in->id_list_size(); i++) for (int i = 0; i < in->id_list_size(); i++)
@ -350,8 +353,6 @@ static command_result ListMaterials(color_ostream &stream,
static command_result ListUnits(color_ostream &stream, static command_result ListUnits(color_ostream &stream,
const ListUnitsIn *in, ListUnitsOut *out) const ListUnitsIn *in, ListUnitsOut *out)
{ {
CoreSuspender suspend;
auto mask = in->has_mask() ? &in->mask() : NULL; auto mask = in->has_mask() ? &in->mask() : NULL;
if (in->id_list_size() > 0) if (in->id_list_size() > 0)
@ -415,14 +416,15 @@ CoreService::CoreService() {
suspend_depth = 0; suspend_depth = 0;
// These 2 methods must be first, so that they get id 0 and 1 // These 2 methods must be first, so that they get id 0 and 1
addMethod("BindMethod", &CoreService::BindMethod); addMethod("BindMethod", &CoreService::BindMethod, SF_DONT_SUSPEND);
addMethod("RunCommand", &CoreService::RunCommand); addMethod("RunCommand", &CoreService::RunCommand, SF_DONT_SUSPEND);
// Add others here: // Add others here:
addMethod("CoreSuspend", &CoreService::CoreSuspend); addMethod("CoreSuspend", &CoreService::CoreSuspend, SF_DONT_SUSPEND);
addMethod("CoreResume", &CoreService::CoreResume); addMethod("CoreResume", &CoreService::CoreResume, SF_DONT_SUSPEND);
addFunction("ListEnums", ListEnums, SF_CALLED_ONCE); // Functions:
addFunction("ListEnums", ListEnums, SF_CALLED_ONCE | SF_DONT_SUSPEND);
addFunction("ListMaterials", ListMaterials, SF_CALLED_ONCE); addFunction("ListMaterials", ListMaterials, SF_CALLED_ONCE);
addFunction("ListUnits", ListUnits); addFunction("ListUnits", ListUnits);
addFunction("ListSquads", ListSquads); addFunction("ListSquads", ListSquads);

@ -43,7 +43,10 @@ namespace DFHack
enum ServerFunctionFlags { enum ServerFunctionFlags {
// The function is expected to be called only once per client, // The function is expected to be called only once per client,
// so always delete all cached buffers after processing. // so always delete all cached buffers after processing.
SF_CALLED_ONCE = 1 SF_CALLED_ONCE = 1,
// Don't automatically suspend the core around the call.
// The function is supposed to manage locking itself.
SF_DONT_SUSPEND = 2
}; };
class DFHACK_EXPORT ServerFunctionBase : public RPCFunctionBase { class DFHACK_EXPORT ServerFunctionBase : public RPCFunctionBase {
@ -225,6 +228,7 @@ namespace DFHack
tthread::thread *thread; tthread::thread *thread;
static void threadFn(void *); static void threadFn(void *);
void threadFn();
public: public:
ServerConnection(CActiveSocket *socket); ServerConnection(CActiveSocket *socket);

@ -5,6 +5,8 @@ option optimize_for = LITE_RUNTIME;
message EnumItemName { message EnumItemName {
required int32 value = 1; required int32 value = 1;
optional string name = 2; optional string name = 2;
// For bitfield members
optional int32 bit_size = 3 [default = 1]; optional int32 bit_size = 3 [default = 1];
}; };
@ -16,10 +18,15 @@ message BasicMaterialId {
message BasicMaterialInfo { message BasicMaterialInfo {
required int32 type = 1; required int32 type = 1;
required sint32 index = 2; required sint32 index = 2;
// The raw token
required string token = 3; required string token = 3;
repeated int32 flags = 4; // of material_flags // IF mask.flags:
// List of material_flags indices
repeated int32 flags = 4;
// Material type/index expanded:
optional int32 subtype = 5 [default = -1]; optional int32 subtype = 5 [default = -1];
optional int32 creature_id = 6 [default = -1]; optional int32 creature_id = 6 [default = -1];
optional int32 plant_id = 7 [default = -1]; optional int32 plant_id = 7 [default = -1];
@ -27,10 +34,13 @@ message BasicMaterialInfo {
optional string name_prefix = 9 [default = ""]; optional string name_prefix = 9 [default = ""];
// IF mask.states: in listed order;
// ELSE: one state matching mask.temperature
repeated fixed32 state_color = 10; repeated fixed32 state_color = 10;
repeated string state_name = 11; repeated string state_name = 11;
repeated string state_adj = 12; repeated string state_adj = 12;
// IF mask.reaction:
message Product { message Product {
required string id = 1; required string id = 1;
required int32 type = 2; required int32 type = 2;
@ -39,6 +49,7 @@ message BasicMaterialInfo {
repeated string reaction_class = 13; repeated string reaction_class = 13;
repeated Product reaction_product = 14; repeated Product reaction_product = 14;
// IF mask.flags:
repeated int32 inorganic_flags = 15; repeated int32 inorganic_flags = 15;
}; };
@ -90,8 +101,10 @@ message BasicUnitInfo {
optional int32 civ_id = 9 [default = -1]; optional int32 civ_id = 9 [default = -1];
optional int32 histfig_id = 10 [default = -1]; optional int32 histfig_id = 10 [default = -1];
// IF mask.labors:
repeated int32 labors = 11; repeated int32 labors = 11;
// IF mask.skills:
repeated SkillInfo skills = 12; repeated SkillInfo skills = 12;
required int32 pos_x = 13; required int32 pos_x = 13;
@ -108,7 +121,10 @@ message BasicSquadInfo {
required int32 squad_id = 1; required int32 squad_id = 1;
optional NameInfo name = 2; optional NameInfo name = 2;
// A special field completely overriding the name:
optional string alias = 3; optional string alias = 3;
// Member histfig ids:
repeated sint32 members = 4; repeated sint32 members = 4;
}; };

@ -18,7 +18,11 @@ message ListEnumsOut {
message ListMaterialsIn { message ListMaterialsIn {
optional BasicMaterialInfoMask mask = 1; optional BasicMaterialInfoMask mask = 1;
// Specific materials:
repeated BasicMaterialId id_list = 2; repeated BasicMaterialId id_list = 2;
// Complete list by type:
optional bool builtin = 3; optional bool builtin = 3;
optional bool inorganic = 4; optional bool inorganic = 4;
optional bool creatures = 5; optional bool creatures = 5;
@ -30,8 +34,11 @@ message ListMaterialsOut {
message ListUnitsIn { message ListUnitsIn {
optional BasicUnitInfoMask mask = 1; optional BasicUnitInfoMask mask = 1;
// Specific units:
repeated int32 id_list = 2; repeated int32 id_list = 2;
// All units matching:
optional int32 race = 3; optional int32 race = 3;
optional int32 civ_id = 4; optional int32 civ_id = 4;
}; };

@ -124,8 +124,6 @@ void setUnitNickname(df::unit *unit, const std::string &nick)
static command_result RenameSquad(color_ostream &stream, const RenameSquadIn *in) static command_result RenameSquad(color_ostream &stream, const RenameSquadIn *in)
{ {
CoreSuspender suspend;
df::squad *squad = df::squad::find(in->squad_id()); df::squad *squad = df::squad::find(in->squad_id());
if (!squad) if (!squad)
return CR_NOT_FOUND; return CR_NOT_FOUND;
@ -140,8 +138,6 @@ static command_result RenameSquad(color_ostream &stream, const RenameSquadIn *in
static command_result RenameUnit(color_ostream &stream, const RenameUnitIn *in) static command_result RenameUnit(color_ostream &stream, const RenameUnitIn *in)
{ {
CoreSuspender suspend;
df::unit *unit = df::unit::find(in->unit_id()); df::unit *unit = df::unit::find(in->unit_id());
if (!unit) if (!unit)
return CR_NOT_FOUND; return CR_NOT_FOUND;