rbtrace 0.3.20 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (6) hide show
  1. data/Gemfile.lock +1 -1
  2. data/bin/rbtrace +31 -9
  3. data/ext/rbtrace.c +45 -35
  4. data/rbtrace.gemspec +1 -1
  5. data/test.sh +1 -1
  6. metadata +1 -1
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rbtrace (0.3.19)
4
+ rbtrace (0.4.0)
5
5
  ffi (>= 1.0.6)
6
6
  msgpack (>= 0.4.3)
7
7
  trollop (>= 1.16.2)
data/bin/rbtrace CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
+ require 'socket'
3
+ require 'fileutils'
2
4
  require 'rubygems'
3
5
  require 'ffi'
4
6
  require 'msgpack'
@@ -154,17 +156,23 @@ class RBTracer
154
156
  raise ArgumentError, 'could not signal process, are you running as root?'
155
157
  end
156
158
 
159
+ path = "/tmp/rbtrace-#{@pid}.sock"
160
+ @sock = Socket.new Socket::AF_UNIX, Socket::SOCK_DGRAM, 0
161
+ @sockaddr = Socket.pack_sockaddr_un(path)
162
+ @sock.bind(@sockaddr)
163
+ FileUtils.chmod 0666, path
164
+ at_exit{ FileUtils.rm(path) if File.exists?(path) }
165
+
157
166
  5.times do
158
167
  signal
159
168
  sleep 0.15 # wait for process to create msgqs
160
169
 
161
- @qi = MsgQ.msgget( pid, 0666)
162
170
  @qo = MsgQ.msgget(-pid, 0666)
163
171
 
164
- break if @qi > -1 || @qo > -1
172
+ break if @qo > -1
165
173
  end
166
174
 
167
- if @qi == -1 || @qo == -1
175
+ if @qo == -1
168
176
  raise ArgumentError, 'pid is not listening for messages, did you `require "rbtrace"`'
169
177
  end
170
178
 
@@ -419,11 +427,13 @@ class RBTracer
419
427
  end
420
428
 
421
429
  def recv_cmd(block=true)
422
- MsgQ::EventMsg.recv_cmd(@qi, block)
423
- rescue Errno::EINTR
424
- # on linux, an incoming signal will interrupt msgrcv()
425
- # regardless of what SA_RESTART is set to
426
- retry
430
+ if block
431
+ @sock.recv(65536)
432
+ else
433
+ @sock.recv_nonblock(65536)
434
+ end
435
+ rescue Errno::EAGAIN
436
+ nil
427
437
  end
428
438
 
429
439
  def valid_syntax?(code)
@@ -811,6 +821,10 @@ EOS
811
821
  :type => String,
812
822
  :short => '-e'
813
823
 
824
+ opt :backtrace,
825
+ "get lines from the current backtrace in the process",
826
+ :type => :int
827
+
814
828
  opt :wait,
815
829
  "seconds to wait before attaching to process",
816
830
  :default => 0,
@@ -834,7 +848,7 @@ EOS
834
848
  ARGV.clear
835
849
  end
836
850
 
837
- unless %w[ fork eval slow slowcpu firehose methods config gc ].find{ |n| opts[:"#{n}_given"] }
851
+ unless %w[ fork eval backtrace slow slowcpu firehose methods config gc ].find{ |n| opts[:"#{n}_given"] }
838
852
  $stderr.puts "Error: --slow, --slowcpu, --gc, --firehose, --methods or --config required."
839
853
  $stderr.puts "Try --help for help."
840
854
  exit(-1)
@@ -1011,6 +1025,14 @@ EOS
1011
1025
  pid = tracer.fork
1012
1026
  STDERR.puts "*** forked off a busy looping copy at #{pid} (make sure to kill -9 it when you're done)"
1013
1027
 
1028
+ elsif opts[:backtrace_given]
1029
+ num = opts[:backtrace]
1030
+ code = "caller.first(#{num}).join('|')"
1031
+
1032
+ if res = tracer.eval(code)
1033
+ tracer.puts res[1..-2].split('|').join("\n ")
1034
+ end
1035
+
1014
1036
  elsif opts[:eval_given]
1015
1037
  if res = tracer.eval(code = opts[:eval])
1016
1038
  tracer.puts ">> #{code}"
data/ext/rbtrace.c CHANGED
@@ -12,8 +12,10 @@
12
12
  #include <sys/ipc.h>
13
13
  #include <sys/msg.h>
14
14
  #include <sys/resource.h>
15
+ #include <sys/socket.h>
15
16
  #include <sys/time.h>
16
17
  #include <sys/types.h>
18
+ #include <sys/un.h>
17
19
  #include <sys/wait.h>
18
20
  #include <time.h>
19
21
  #include <unistd.h>
@@ -108,11 +110,13 @@ static struct {
108
110
  unsigned int num_slow;
109
111
  rbtracer_t list[MAX_TRACERS];
110
112
 
111
- key_t mqo_key;
112
113
  key_t mqi_key;
113
- int mqo_id;
114
114
  int mqi_id;
115
115
 
116
+ int mqo_fd;
117
+ struct sockaddr_un mqo_addr;
118
+ socklen_t mqo_len;
119
+
116
120
  msgpack_sbuffer *sbuf;
117
121
  msgpack_packer *msgpacker;
118
122
  }
@@ -137,11 +141,12 @@ rbtracer = {
137
141
  .num_slow = 0,
138
142
  .list = {},
139
143
 
140
- .mqo_key = 0,
141
144
  .mqi_key = 0,
142
- .mqo_id = -1,
143
145
  .mqi_id = -1,
144
146
 
147
+ .mqo_fd = -1,
148
+ .mqo_addr = {.sun_family = AF_UNIX},
149
+
145
150
  .sbuf = NULL,
146
151
  .msgpacker = NULL
147
152
  };
@@ -156,7 +161,7 @@ rbtrace__send_event(int nargs, const char *name, ...)
156
161
  if (!rbtracer.attached_pid ||
157
162
  !rbtracer.sbuf ||
158
163
  !rbtracer.msgpacker ||
159
- rbtracer.mqo_id == -1)
164
+ rbtracer.mqo_fd == -1)
160
165
  return;
161
166
 
162
167
  int n;
@@ -232,31 +237,26 @@ rbtrace__send_event(int nargs, const char *name, ...)
232
237
  va_end(ap);
233
238
  }
234
239
 
235
- event_msg_t msg;
236
- msg.mtype = 1;
237
-
238
- if (rbtracer.sbuf->size > sizeof(msg.buf)) {
239
- fprintf(stderr, "rbtrace__send_event(): message is too large (%zd > %zu)\n", rbtracer.sbuf->size, sizeof(msg.buf));
240
- return;
241
- }
242
-
243
- memcpy(msg.buf, rbtracer.sbuf->data, rbtracer.sbuf->size);
244
-
245
240
  int ret = -1;
246
241
  for (n=0; n<10 && ret==-1; n++)
247
- ret = msgsnd(rbtracer.mqo_id, &msg, sizeof(msg)-sizeof(long), IPC_NOWAIT);
242
+ ret = sendto(
243
+ rbtracer.mqo_fd,
244
+ rbtracer.sbuf->data, rbtracer.sbuf->size,
245
+ #ifdef MSG_NOSIGNAL
246
+ MSG_NOSIGNAL,
247
+ #else
248
+ 0,
249
+ #endif
250
+ &rbtracer.mqo_addr, rbtracer.mqo_len
251
+ );
248
252
 
249
- if (ret == -1 && errno == EINVAL) {
250
- fprintf(stderr, "msgsnd(%d): %s [detaching]\n", rbtracer.mqo_id, strerror(errno));
253
+ if (ret == -1 && (errno == EINVAL || errno == ENOENT || errno == ECONNREFUSED || errno == EPIPE)) {
254
+ fprintf(stderr, "sendto(%d): %s [detaching]\n", rbtracer.mqo_fd, strerror(errno));
251
255
 
252
256
  msgq_teardown();
253
257
  rbtracer_detach();
254
258
  } else if (ret == -1) {
255
- fprintf(stderr, "msgsnd(%d): %s\n", rbtracer.mqo_id, strerror(errno));
256
-
257
- struct msqid_ds stat;
258
- msgctl(rbtracer.mqo_id, IPC_STAT, &stat);
259
- fprintf(stderr, "cbytes: %lu, qbytes: %lu, qnum: %lu\n", stat.msg_cbytes, stat.msg_qbytes, stat.msg_qnum);
259
+ fprintf(stderr, "sendto(%d): %s\n", rbtracer.mqo_fd, strerror(errno));
260
260
  }
261
261
  }
262
262
 
@@ -797,11 +797,11 @@ msgq_teardown()
797
797
  {
798
798
  pid_t pid = getpid();
799
799
 
800
- if (rbtracer.mqo_id != -1 && rbtracer.mqo_key == (key_t)pid) {
801
- msgctl(rbtracer.mqo_id, IPC_RMID, NULL);
802
- rbtracer.mqo_id = -1;
803
- rbtracer.mqo_key = 0;
800
+ if (rbtracer.mqo_fd != -1) {
801
+ close(rbtracer.mqo_fd);
802
+ rbtracer.mqo_fd = -1;
804
803
  }
804
+
805
805
  if (rbtracer.mqi_id != -1 && rbtracer.mqi_key == (key_t)-pid) {
806
806
  msgctl(rbtracer.mqi_id, IPC_RMID, NULL);
807
807
  rbtracer.mqi_id = -1;
@@ -819,26 +819,36 @@ static inline void
819
819
  msgq_setup()
820
820
  {
821
821
  pid_t pid = getpid();
822
+ int val;
822
823
 
823
- if (rbtracer.mqo_key != (key_t)pid ||
824
- rbtracer.mqi_key != (key_t)-pid) {
824
+ if (rbtracer.mqi_key != (key_t)-pid ||
825
+ rbtracer.mqo_fd == -1) {
825
826
  msgq_teardown();
826
827
  } else {
827
828
  return;
828
829
  }
829
830
 
830
- rbtracer.mqo_key = (key_t) pid;
831
- rbtracer.mqo_id = msgget(rbtracer.mqo_key, 0666 | IPC_CREAT);
832
-
833
- if (rbtracer.mqo_id == -1)
834
- fprintf(stderr, "msgget() failed to create msgq\n");
835
-
836
831
 
837
832
  rbtracer.mqi_key = (key_t) -pid;
838
833
  rbtracer.mqi_id = msgget(rbtracer.mqi_key, 0666 | IPC_CREAT);
839
834
 
840
835
  if (rbtracer.mqi_id == -1)
841
836
  fprintf(stderr, "msgget() failed to create msgq\n");
837
+
838
+
839
+ rbtracer.mqo_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
840
+ if (rbtracer.mqo_fd == -1)
841
+ fprintf(stderr, "socket() failed to create dgram\n");
842
+
843
+ snprintf(rbtracer.mqo_addr.sun_path, sizeof(rbtracer.mqo_addr.sun_path), "/tmp/rbtrace-%d.sock", pid);
844
+ rbtracer.mqo_len = SUN_LEN(&rbtracer.mqo_addr);
845
+
846
+ val = 65536;
847
+ setsockopt(rbtracer.mqo_fd, SOL_SOCKET, SO_SNDBUF, &val, sizeof(int));
848
+ #ifdef SO_NOSIGPIPE
849
+ val = 1;
850
+ setsockopt(rbtracer.mqo_fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(int));
851
+ #endif
842
852
  }
843
853
 
844
854
  static void
data/rbtrace.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'rbtrace'
3
- s.version = '0.3.20'
3
+ s.version = '0.4.0'
4
4
  s.homepage = 'http://github.com/tmm1/rbtrace'
5
5
 
6
6
  s.authors = 'Aman Gupta'
data/test.sh CHANGED
@@ -42,6 +42,6 @@ trace --slow=250 --slow-methods sleep
42
42
  trace --gc -m Dir. --slow=250 --slow-methods sleep
43
43
  trace --gc -m Dir. --slow=250
44
44
  trace -m Process. Dir.pwd "Proc#call"
45
- # trace --firehose
45
+ trace --firehose
46
46
 
47
47
  cleanup
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: rbtrace
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.3.20
5
+ version: 0.4.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Aman Gupta