use property setter in debug mode to map seq num to stack trace

This commit is contained in:
Andrey Sidorov 2014-03-08 18:04:09 +11:00
parent d436abf9b9
commit 56001da581

View file

@ -64,8 +64,26 @@ function XClient(stream, displayNum, screenNum, options)
this.pack_stream = pack_stream;
this.rsrc_id = 0; // generated for each new resource
this.seq_num = 0; // incremented in each request. (even if we don't expect reply)
this.seq2stack = {}; // debug: map seq_num to stack at the moment request was issued
var cli = this;
if (cli.options.debug) {
this.seq_num_ = 0;
this.seq2stack = {}; // debug: map seq_num to stack at the moment request was issued
Object.defineProperty(cli, "seq_num", {
set : function(v) {
cli.seq_num_ = v;
var err = new Error();
Error.captureStackTrace(err, arguments.callee);
err.timestamp = Date.now();
cli.seq2stack[client.seq_num] = err;
},
get: function() {
return cli.seq_num_;
}
});
} else {
this.seq_num = 0;
}
// in/out packets indexed by sequence ID
this.replies = {};
@ -83,6 +101,7 @@ function XClient(stream, displayNum, screenNum, options)
this.event_consumers = {}; // maps window id to eventemitter TODO: bad name
this.eventParsers = {};
this.errorParsers = {};
this.importRequestsFromTemplates(this, coreRequests);
@ -138,18 +157,6 @@ XClient.prototype.importRequestsFromTemplates = function(target, reqs)
else
client.seq_num++;
// disable long stack trace for the moment, it's too expensive
// performance when enabled (travis-ci worker, Xfvb): 70000 requests finished in 52196 ms, 1341.0989347842747 req/sec
// without: 70000 requests finished in 14904 ms, 4696.725711218465 req/sec
// MBPro, XQuartz: with 3600 req/sec, without 24200 req/sec
if (this.options.debug === true) {
var err = new Error();
err.name = reqName; //???
Error.captureStackTrace(err, arguments.callee);
err.timestamp = Date.now();
client.seq2stack[client.seq_num] = err;
}
// is it fast?
var args = Array.prototype.slice.call(req_proxy.arguments);
@ -171,7 +178,7 @@ XClient.prototype.importRequestsFromTemplates = function(target, reqs)
var value = req_proxy.arguments[1];
if (client.atoms[value]) {
-- client.seq_num;
return process.nextTick(function() {
return setImmediate(function() {
callback(undefined, client.atoms[value]);
});
} else {
@ -197,7 +204,7 @@ XClient.prototype.importRequestsFromTemplates = function(target, reqs)
var atom = req_proxy.arguments[0];
if (client.atom_names[atom]) {
-- client.seq_num;
return process.nextTick(function() {
return setImmediate(function() {
callback(undefined, client.atom_names[atom]);
});
} else {
@ -412,12 +419,22 @@ XClient.prototype.expectReplyHeader = function()
error.error = error_code;
error.seq = seq_num;
error.message = xerrors.errorText[error_code];
if (client.options.debug)
error.stack = client.seq2stack[error.seq]
if (client.options.debug) {
error.longstack = client.seq2stack[error.seq]
console.log(client.seq2stack[error.seq].stack);
}
// unpack error packet (32 bytes for all error types, 8 of them in CCSL header)
client.pack_stream.get(24, function(buf) {
var extUnpacker = client.errorParsers[type];
if (extUnpacker) {
var event = extUnpacker(type, seq_num, bad_value, body);
client.emit(error, event);
client.expectReplyHeader();
return;
}
// TODO: dispatch, use sequence number
//TODO: add more generic way to read common values
// if (error_code == 14)
@ -569,26 +586,30 @@ module.exports.createClient = function(options, initCb)
var client = new XClient(stream, displayNum, screenNum, options);
if (initCb)
{
var cbCalled = false;
client.on('connect', function(display) {
// Once connected don't call initCb on error, just emit
stream.removeListener('error', initCb);
stream.on('error', function(err) {
client.emit('error', err);
});
// opt-in BigReq
if (!options.disableBigRequests) {
client.require('big-requests', function(BigReq) {
BigReq.Enable(function(err, maxLen) {
display.max_request_length = maxLen;
cbCalled = true;
initCb(undefined, display);
});
});
} else {
cbCalled = true;
initCb(undefined, display);
}
});
stream.on('error', initCb);
stream.on('error', function(err) {
if (cbCalled)
client.emit('error', err);
else {
cbCalled = true;
initCb(err);
}
});
}
return client;
}