agoo 2.5.7 → 2.6.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.

Potentially problematic release.


This version of agoo might be problematic. Click here for more details.

Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +38 -0
  4. data/ext/agoo/agoo.c +11 -2
  5. data/ext/agoo/bind.c +15 -20
  6. data/ext/agoo/con.c +32 -25
  7. data/ext/agoo/debug.c +225 -162
  8. data/ext/agoo/debug.h +31 -51
  9. data/ext/agoo/doc.c +278 -5
  10. data/ext/agoo/doc.h +6 -1
  11. data/ext/agoo/err.c +1 -0
  12. data/ext/agoo/err.h +1 -0
  13. data/ext/agoo/error_stream.c +3 -6
  14. data/ext/agoo/gqlcobj.c +12 -0
  15. data/ext/agoo/gqlcobj.h +25 -0
  16. data/ext/agoo/gqleval.c +520 -0
  17. data/ext/agoo/gqleval.h +49 -0
  18. data/ext/agoo/gqlintro.c +1237 -97
  19. data/ext/agoo/gqlintro.h +8 -0
  20. data/ext/agoo/gqljson.c +460 -0
  21. data/ext/agoo/gqljson.h +15 -0
  22. data/ext/agoo/gqlvalue.c +679 -136
  23. data/ext/agoo/gqlvalue.h +29 -7
  24. data/ext/agoo/graphql.c +841 -362
  25. data/ext/agoo/graphql.h +180 -90
  26. data/ext/agoo/hook.c +8 -16
  27. data/ext/agoo/http.c +3 -4
  28. data/ext/agoo/log.c +22 -25
  29. data/ext/agoo/log.h +1 -0
  30. data/ext/agoo/page.c +24 -40
  31. data/ext/agoo/pub.c +23 -21
  32. data/ext/agoo/queue.c +2 -4
  33. data/ext/agoo/ready.c +9 -9
  34. data/ext/agoo/req.c +80 -5
  35. data/ext/agoo/req.h +2 -0
  36. data/ext/agoo/res.c +1 -3
  37. data/ext/agoo/rgraphql.c +753 -0
  38. data/ext/agoo/rresponse.c +9 -15
  39. data/ext/agoo/rserver.c +18 -17
  40. data/ext/agoo/sdl.c +1264 -120
  41. data/ext/agoo/sdl.h +8 -1
  42. data/ext/agoo/sectime.c +136 -0
  43. data/ext/agoo/sectime.h +19 -0
  44. data/ext/agoo/server.c +1 -3
  45. data/ext/agoo/subject.c +2 -4
  46. data/ext/agoo/text.c +124 -18
  47. data/ext/agoo/text.h +5 -1
  48. data/ext/agoo/upgraded.c +2 -4
  49. data/lib/agoo/version.rb +1 -1
  50. data/test/base_handler_test.rb +43 -40
  51. data/test/bind_test.rb +49 -48
  52. data/test/graphql_test.rb +1019 -0
  53. data/test/hijack_test.rb +1 -1
  54. data/test/rack_handler_test.rb +40 -34
  55. data/test/static_test.rb +33 -32
  56. metadata +17 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cf9915f94b902db5415c971deaa9b1acbcf1a293656958fe78b4b467256ce858
4
- data.tar.gz: 3e6a90cff696e575faa58cd5e18af23234eedab8c0478f5ecb5ec8b385de56e4
3
+ metadata.gz: 2777518b8ae392fd175eb2a70e10ddc88698c8a1a7c2435fb02a210017d401ad
4
+ data.tar.gz: c2020e0aeca0163470c3501a0f718df32170039520d117d1b1a5b939f68840b6
5
5
  SHA512:
6
- metadata.gz: 773278757468ee34167b62a2cbf41d0c35caf3240b595d5b500222045acd247273317f84fd9e25dc8b1dfbe2afce1585bbfcda360e458c15e9a28493dc078938
7
- data.tar.gz: 68fadbf82b989ebc4ae2deb35209f5aff9f7d1a6a289b8d53cbab8c7930a44e93ba9515a36e15d5ed0fb9d3e6717d2c0678606c6b9c62330839b278b4e59c41b
6
+ metadata.gz: e60ec30b4b6f0ce6f8a5b98faf79ca5facd28bd435be0f91ebbfcf0f9ba8678e79f6fa279cc8ab7ad38b1eec99c7c76d9f171c46e377646dd9ad25df22d6c937
7
+ data.tar.gz: 565408d7edf87f3d6d3f26534447c98c3cd4dc545685576d36252684885e23e05c097579318dfc9b2ab6ff23fbfda5868383374c6f97b0f88b599f5e488aee25
@@ -1,5 +1,11 @@
1
1
  # CHANGELOG
2
2
 
3
+ ### 2.6.0 - 2019-01-20
4
+
5
+ GraphQL supported with a simple, easy to use API. Existing API remain the same but a new Agoo::GraphQL module has been added along with supporting examples.
6
+
7
+ - Replaced the use of `gmtime` with an included function to assure support for dates before 1970.
8
+
3
9
  ### 2.5.7 - 2018-12-03
4
10
 
5
11
  Bad release fix along with upload example.
data/README.md CHANGED
@@ -8,6 +8,8 @@ A High Performance HTTP Server for Ruby
8
8
 
9
9
  ## Usage
10
10
 
11
+ #### Rack
12
+
11
13
  ```ruby
12
14
  require 'agoo'
13
15
 
@@ -29,6 +31,38 @@ Agoo::Server.start()
29
31
  # ruby hello.rb
30
32
  ```
31
33
 
34
+ #### GraphQL
35
+
36
+ ```ruby
37
+ require 'agoo'
38
+
39
+ class Query
40
+ def hello
41
+ 'hello'
42
+ end
43
+ end
44
+
45
+ class Schema
46
+ attr_reader :query
47
+
48
+ def initialize
49
+ @query = Query.new()
50
+ end
51
+ end
52
+
53
+ Agoo::Server.init(6464, 'root', thread_count: 1, graphql: '/graphql')
54
+ Agoo::Server.start()
55
+ Agoo::GraphQL.schema(Schema.new) {
56
+ Agoo::GraphQL.load(%^type Query { hello: String }^)
57
+ }
58
+ sleep
59
+
60
+ # To run this GraphQL example type the following then go to a browser and enter
61
+ # a URL of localhost:6464/graphql?query={hello}
62
+ #
63
+ # ruby hello.rb
64
+ ```
65
+
32
66
  ## Installation
33
67
  ```
34
68
  gem install agoo
@@ -54,6 +88,10 @@ Agoo is not available on Windows.
54
88
 
55
89
  ## News
56
90
 
91
+ - Agoo has a new GraphQL module with a simple, easy to use
92
+ API. Checkout the [hello](example/graphql/hello.rb) or
93
+ [song](example/graphql/song.rb) examples.
94
+
57
95
  - Agoo takes first place as the highest throughput on [web-frameworks
58
96
  benchmarks](https://github.com/the-benchmarker/web-frameworks). Latency was
59
97
  not at the top but release 2.5.2 improves that. Look for an Agoo-C benchmark
@@ -7,6 +7,7 @@
7
7
 
8
8
  #include "debug.h"
9
9
  #include "error_stream.h"
10
+ #include "graphql.h"
10
11
  #include "log.h"
11
12
  #include "pub.h"
12
13
  #include "rack_logger.h"
@@ -18,6 +19,8 @@
18
19
  #include "server.h"
19
20
  #include "upgraded.h"
20
21
 
22
+ extern void graphql_init(VALUE mod);
23
+
21
24
  void
22
25
  agoo_shutdown() {
23
26
  rserver_shutdown(Qnil);
@@ -33,7 +36,9 @@ agoo_shutdown() {
33
36
  static VALUE
34
37
  ragoo_shutdown(VALUE self) {
35
38
  agoo_shutdown();
36
- debug_rreport();
39
+ gql_destroy();
40
+ debug_report();
41
+
37
42
  return Qnil;
38
43
  }
39
44
 
@@ -74,8 +79,11 @@ ragoo_unsubscribe(VALUE self, VALUE subject) {
74
79
 
75
80
  static void
76
81
  sig_handler(int sig) {
82
+ #ifdef MEM_DEBUG
83
+ rb_gc();
84
+ #endif
77
85
  agoo_shutdown();
78
-
86
+ gql_destroy();
79
87
  debug_report();
80
88
  // Use exit instead of rb_exit as rb_exit segfaults most of the time.
81
89
  //rb_exit(0);
@@ -99,6 +107,7 @@ Init_agoo() {
99
107
  response_init(mod);
100
108
  server_init(mod);
101
109
  upgraded_init(mod);
110
+ graphql_init(mod);
102
111
 
103
112
  rb_define_module_function(mod, "shutdown", ragoo_shutdown, 0);
104
113
  rb_define_module_function(mod, "publish", ragoo_publish, 2);
@@ -15,18 +15,17 @@
15
15
 
16
16
  agooBind
17
17
  agoo_bind_port(agooErr err, int port) {
18
- agooBind b = (agooBind)malloc(sizeof(struct _agooBind));
18
+ agooBind b = (agooBind)AGOO_MALLOC(sizeof(struct _agooBind));
19
19
 
20
20
  if (NULL != b) {
21
21
  char id[1024];
22
22
 
23
- DEBUG_ALLOC(mem_bind, b);
24
23
  memset(b, 0, sizeof(struct _agooBind));
25
24
  b->port = port;
26
25
  b->family = AF_INET;
27
26
  snprintf(id, sizeof(id) - 1, "http://:%d", port);
28
27
  strcpy(b->scheme, "http");
29
- if (NULL == (b->id = strdup(id))) {
28
+ if (NULL == (b->id = AGOO_STRDUP(id))) {
30
29
  agoo_err_set(err, AGOO_ERR_MEMORY, "strdup of bind id failed.");
31
30
  return NULL;
32
31
  }
@@ -63,17 +62,16 @@ url_tcp(agooErr err, const char *url, const char *scheme) {
63
62
  }
64
63
  port = atoi(colon + 1);
65
64
  }
66
- if (NULL != (b = (agooBind)malloc(sizeof(struct _agooBind)))) {
65
+ if (NULL != (b = (agooBind)AGOO_MALLOC(sizeof(struct _agooBind)))) {
67
66
  char id[64];
68
67
 
69
- DEBUG_ALLOC(mem_bind, b);
70
68
  memset(b, 0, sizeof(struct _agooBind));
71
69
 
72
70
  b->port = port;
73
71
  b->addr4 = addr;
74
72
  b->family = AF_INET;
75
73
  snprintf(id, sizeof(id), "%s://%s:%d", scheme, inet_ntoa(addr), port);
76
- if (NULL == (b->id = strdup(id))) {
74
+ if (NULL == (b->id = AGOO_STRDUP(id))) {
77
75
  agoo_err_set(err, AGOO_ERR_MEMORY, "strdup of bind id failed.");
78
76
  return NULL;
79
77
  }
@@ -109,17 +107,16 @@ url_tcp6(agooErr err, const char *url, const char *scheme) {
109
107
  agoo_err_set(err, AGOO_ERR_ARG, "%s bind address is not valid. (%s)", scheme, url);
110
108
  return NULL;
111
109
  }
112
- if (NULL != (b = (agooBind)malloc(sizeof(struct _agooBind)))) {
110
+ if (NULL != (b = (agooBind)AGOO_MALLOC(sizeof(struct _agooBind)))) {
113
111
  char str[INET6_ADDRSTRLEN + 1];
114
112
 
115
- DEBUG_ALLOC(mem_bind, b);
116
113
  memset(b, 0, sizeof(struct _agooBind));
117
114
 
118
115
  b->port = port;
119
116
  b->addr6 = addr;
120
117
  b->family = AF_INET6;
121
118
  snprintf(buf, sizeof(buf), "%s://[%s]:%d", scheme, inet_ntop(AF_INET6, &addr, str, INET6_ADDRSTRLEN), port);
122
- if (NULL == (b->id = strdup(buf))) {
119
+ if (NULL == (b->id = AGOO_STRDUP(buf))) {
123
120
  agoo_err_set(err, AGOO_ERR_MEMORY, "strdup of bind id failed.");
124
121
  return NULL;
125
122
  }
@@ -143,20 +140,19 @@ url_named(agooErr err, const char *url) {
143
140
  agoo_err_set(err, AGOO_ERR_ARG, "Named Unix sockets names must not be empty.");
144
141
  return NULL;
145
142
  } else {
146
- agooBind b = (agooBind)malloc(sizeof(struct _agooBind));
143
+ agooBind b = (agooBind)AGOO_MALLOC(sizeof(struct _agooBind));
147
144
 
148
145
  if (NULL != b) {
149
146
  const char *fmt = "unix://%s";
150
147
  char id[1024];
151
148
 
152
- DEBUG_ALLOC(mem_bind, b);
153
149
  memset(b, 0, sizeof(struct _agooBind));
154
- if (NULL == (b->name = strdup(url))) {
150
+ if (NULL == (b->name = AGOO_STRDUP(url))) {
155
151
  agoo_err_set(err, AGOO_ERR_MEMORY, "strdup of bind url failed.");
156
152
  return NULL;
157
153
  }
158
154
  snprintf(id, sizeof(id) - 1, fmt, url);
159
- if (NULL == (b->id = strdup(id))) {
155
+ if (NULL == (b->id = AGOO_STRDUP(id))) {
160
156
  agoo_err_set(err, AGOO_ERR_MEMORY, "strdup of bind id failed.");
161
157
  return NULL;
162
158
  }
@@ -223,13 +219,12 @@ agoo_bind_url(agooErr err, const char *url) {
223
219
 
224
220
  void
225
221
  agoo_bind_destroy(agooBind b) {
226
- DEBUG_FREE(mem_bind, b);
227
- free(b->id);
228
- free(b->name);
229
- free(b->key);
230
- free(b->cert);
231
- free(b->ca);
232
- free(b);
222
+ AGOO_FREE(b->id);
223
+ AGOO_FREE(b->name);
224
+ AGOO_FREE(b->key);
225
+ AGOO_FREE(b->cert);
226
+ AGOO_FREE(b->ca);
227
+ AGOO_FREE(b);
233
228
  }
234
229
 
235
230
  static int
@@ -58,10 +58,9 @@ agooCon
58
58
  agoo_con_create(agooErr err, int sock, uint64_t id, agooBind b) {
59
59
  agooCon c;
60
60
 
61
- if (NULL == (c = (agooCon)malloc(sizeof(struct _agooCon)))) {
61
+ if (NULL == (c = (agooCon)AGOO_MALLOC(sizeof(struct _agooCon)))) {
62
62
  agoo_err_set(err, AGOO_ERR_MEMORY, "Failed to allocate memory for a connection.");
63
63
  } else {
64
- DEBUG_ALLOC(mem_con, c)
65
64
  memset(c, 0, sizeof(struct _agooCon));
66
65
  c->sock = sock;
67
66
  c->id = id;
@@ -74,6 +73,8 @@ agoo_con_create(agooErr err, int sock, uint64_t id, agooBind b) {
74
73
 
75
74
  void
76
75
  agoo_con_destroy(agooCon c) {
76
+ agooRes res;
77
+
77
78
  atomic_fetch_sub(&agoo_server.con_cnt, 1);
78
79
 
79
80
  if (AGOO_CON_WS == c->bind->kind || AGOO_CON_SSE == c->bind->kind) {
@@ -91,8 +92,12 @@ agoo_con_destroy(agooCon c) {
91
92
  c->up = NULL;
92
93
  }
93
94
  agoo_log_cat(&agoo_con_cat, "Connection %llu closed.", (unsigned long long)c->id);
94
- DEBUG_FREE(mem_con, c);
95
- free(c);
95
+
96
+ while (NULL != (res = c->res_head)) {
97
+ c->res_head = res->next;
98
+ AGOO_FREE(res);
99
+ }
100
+ AGOO_FREE(c);
96
101
  }
97
102
 
98
103
  const char*
@@ -789,7 +794,6 @@ con_sse_write(agooCon c) {
789
794
  ssize_t cnt;
790
795
 
791
796
  if (NULL == message) {
792
- agoo_ws_req_close(c);
793
797
  agoo_res_destroy(res);
794
798
 
795
799
  return false;
@@ -799,7 +803,7 @@ con_sse_write(agooCon c) {
799
803
  agooText t;
800
804
 
801
805
  if (agoo_push_cat.on) {
802
- agoo_log_cat(&agoo_push_cat, "%llu: %s", (unsigned long long)c->id, message->text);
806
+ agoo_log_cat(&agoo_push_cat, "%llu: %s %p", (unsigned long long)c->id, message->text, (void*)res);
803
807
  }
804
808
  t = agoo_sse_expand(message);
805
809
  if (t != message) {
@@ -817,7 +821,6 @@ con_sse_write(agooCon c) {
817
821
  len = snprintf(msg, sizeof(msg) - 1, "Socket error @ %llu.", (unsigned long long)c->id);
818
822
  push_error(c->up, msg, len);
819
823
  agoo_log_cat(&agoo_error_cat, "Socket error @ %llu.", (unsigned long long)c->id);
820
- agoo_ws_req_close(c);
821
824
 
822
825
  return false;
823
826
  }
@@ -839,13 +842,13 @@ con_sse_write(agooCon c) {
839
842
  }
840
843
 
841
844
  static void
842
- publish_pub(agooPub pub) {
845
+ publish_pub(agooPub pub, agooConLoop loop) {
843
846
  agooUpgraded up;
844
847
  const char *sub = pub->subject->pattern;
845
848
  int cnt = 0;
846
-
849
+
847
850
  for (up = agoo_server.up_list; NULL != up; up = up->next) {
848
- if (NULL != up->con && agoo_upgraded_match(up, sub)) {
851
+ if (NULL != up->con && up->con->loop == loop && agoo_upgraded_match(up, sub)) {
849
852
  agooRes res = agoo_res_create(up->con);
850
853
 
851
854
  if (NULL != res) {
@@ -877,10 +880,10 @@ unsubscribe_pub(agooPub pub) {
877
880
  }
878
881
 
879
882
  static void
880
- process_pub_con(agooPub pub) {
883
+ process_pub_con(agooPub pub, agooConLoop loop) {
881
884
  agooUpgraded up = pub->up;
882
885
 
883
- if (NULL != up) {
886
+ if (NULL != up && NULL != up->con && up->con->loop == loop) {
884
887
  int pending;
885
888
 
886
889
  // TBD Change pending to be based on length of con queue
@@ -901,7 +904,7 @@ process_pub_con(agooPub pub) {
901
904
  // A close after already closed is used to decrement the reference
902
905
  // count on the upgraded so it can be destroyed in the con loop
903
906
  // threads.
904
- if (NULL != up->con) {
907
+ if (NULL != up->con && up->con->loop == loop) {
905
908
  agooRes res = agoo_res_create(up->con);
906
909
 
907
910
  if (NULL != res) {
@@ -919,7 +922,7 @@ process_pub_con(agooPub pub) {
919
922
  case AGOO_PUB_WRITE: {
920
923
  if (NULL == up->con) {
921
924
  agoo_log_cat(&agoo_warn_cat, "Connection already closed. WebSocket write failed.");
922
- } else {
925
+ } else if (up->con->loop == loop) {
923
926
  agooRes res = agoo_res_create(up->con);
924
927
 
925
928
  if (NULL != res) {
@@ -935,14 +938,18 @@ process_pub_con(agooPub pub) {
935
938
  }
936
939
  break;
937
940
  case AGOO_PUB_SUB:
938
- agoo_upgraded_add_subject(pub->up, pub->subject);
939
- pub->subject = NULL;
941
+ if (NULL != up && up->con->loop == loop) {
942
+ agoo_upgraded_add_subject(pub->up, pub->subject);
943
+ pub->subject = NULL;
944
+ }
940
945
  break;
941
946
  case AGOO_PUB_UN:
942
- unsubscribe_pub(pub);
947
+ if (NULL != up && up->con->loop == loop) {
948
+ unsubscribe_pub(pub);
949
+ }
943
950
  break;
944
951
  case AGOO_PUB_MSG:
945
- publish_pub(pub);
952
+ publish_pub(pub, loop);
946
953
  break;
947
954
  }
948
955
  default:
@@ -1053,6 +1060,8 @@ con_ready_read(agooReady ready, void *ctx) {
1053
1060
  if (!c->bind->read(c)) {
1054
1061
  return true;
1055
1062
  }
1063
+ } else {
1064
+ return true; // not an error, just ignore
1056
1065
  }
1057
1066
  return false;
1058
1067
  }
@@ -1138,7 +1147,7 @@ pub_queue_ready_read(agooReady ready, void *ctx) {
1138
1147
 
1139
1148
  agoo_queue_release(&loop->pub_queue);
1140
1149
  while (NULL != (pub = (agooPub)agoo_queue_pop(&loop->pub_queue, 0.0))) {
1141
- process_pub_con(pub);
1150
+ process_pub_con(pub, loop);
1142
1151
  }
1143
1152
  return true;
1144
1153
  }
@@ -1185,7 +1194,7 @@ agoo_con_loop(void *x) {
1185
1194
  }
1186
1195
  }
1187
1196
  while (NULL != (pub = (agooPub)agoo_queue_pop(&loop->pub_queue, 0.0))) {
1188
- process_pub_con(pub);
1197
+ process_pub_con(pub, loop);
1189
1198
  }
1190
1199
  if (AGOO_ERR_OK != agoo_ready_go(&err, ready)) {
1191
1200
  agoo_log_cat(&agoo_error_cat, "IO error. %s", err.msg);
@@ -1202,12 +1211,11 @@ agooConLoop
1202
1211
  agoo_conloop_create(agooErr err, int id) {
1203
1212
  agooConLoop loop;
1204
1213
 
1205
- if (NULL == (loop = (agooConLoop)malloc(sizeof(struct _agooConLoop)))) {
1214
+ if (NULL == (loop = (agooConLoop)AGOO_MALLOC(sizeof(struct _agooConLoop)))) {
1206
1215
  agoo_err_set(err, AGOO_ERR_MEMORY, "Failed to allocate memory for a connection thread.");
1207
1216
  } else {
1208
1217
  int stat;
1209
1218
 
1210
- //DEBUG_ALLOC(mem_con, c);
1211
1219
  loop->next = NULL;
1212
1220
  agoo_queue_multi_init(&loop->pub_queue, 256, true, false);
1213
1221
  loop->id = id;
@@ -1229,8 +1237,7 @@ agoo_conloop_destroy(agooConLoop loop) {
1229
1237
  agoo_queue_cleanup(&loop->pub_queue);
1230
1238
  while (NULL != (res = loop->res_head)) {
1231
1239
  loop->res_head = res->next;
1232
- DEBUG_FREE(mem_res, res);
1233
- free(res);
1240
+ AGOO_FREE(res);
1234
1241
  }
1235
- free(loop);
1242
+ AGOO_FREE(loop);
1236
1243
  }
@@ -2,213 +2,276 @@
2
2
 
3
3
  #include <pthread.h>
4
4
  #include <stdbool.h>
5
+ #include <stdint.h>
5
6
  #include <stdio.h>
6
7
  #include <stdlib.h>
7
-
8
- //#include <ruby.h>
9
- //#include <ruby/thread.h>
8
+ #include <string.h>
10
9
 
11
10
  #include "debug.h"
12
11
 
13
12
  typedef struct _rec {
14
13
  struct _rec *next;
15
- void *ptr;
16
- const char *type;
14
+ const void *ptr;
15
+ size_t size;
17
16
  const char *file;
18
17
  int line;
19
18
  } *Rec;
20
19
 
21
- static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
22
- static Rec recs = NULL;
23
-
24
- atomic_int mem_bind = AGOO_ATOMIC_INT_INIT(0);
25
- atomic_int mem_cb = AGOO_ATOMIC_INT_INIT(0);
26
- atomic_int mem_con = AGOO_ATOMIC_INT_INIT(0);
27
- atomic_int mem_cslot = AGOO_ATOMIC_INT_INIT(0);
28
- atomic_int mem_err_stream = AGOO_ATOMIC_INT_INIT(0);
29
- atomic_int mem_eval_threads = AGOO_ATOMIC_INT_INIT(0);
30
- atomic_int mem_group = AGOO_ATOMIC_INT_INIT(0);
31
- atomic_int mem_graphql_arg = AGOO_ATOMIC_INT_INIT(0);
32
- atomic_int mem_graphql_directive = AGOO_ATOMIC_INT_INIT(0);
33
- atomic_int mem_graphql_field = AGOO_ATOMIC_INT_INIT(0);
34
- atomic_int mem_graphql_link = AGOO_ATOMIC_INT_INIT(0);
35
- atomic_int mem_graphql_slot = AGOO_ATOMIC_INT_INIT(0);
36
- atomic_int mem_graphql_type = AGOO_ATOMIC_INT_INIT(0);
37
- atomic_int mem_graphql_value = AGOO_ATOMIC_INT_INIT(0);
38
- atomic_int mem_group_path = AGOO_ATOMIC_INT_INIT(0);
39
- atomic_int mem_header = AGOO_ATOMIC_INT_INIT(0);
40
- atomic_int mem_hook = AGOO_ATOMIC_INT_INIT(0);
41
- atomic_int mem_hook_pattern = AGOO_ATOMIC_INT_INIT(0);
42
- atomic_int mem_http_slot = AGOO_ATOMIC_INT_INIT(0);
43
- atomic_int mem_log_entry = AGOO_ATOMIC_INT_INIT(0);
44
- atomic_int mem_log_what = AGOO_ATOMIC_INT_INIT(0);
45
- atomic_int mem_log_tid = AGOO_ATOMIC_INT_INIT(0);
46
- atomic_int mem_mime_slot = AGOO_ATOMIC_INT_INIT(0);
47
- atomic_int mem_page = AGOO_ATOMIC_INT_INIT(0);
48
- atomic_int mem_page_msg = AGOO_ATOMIC_INT_INIT(0);
49
- atomic_int mem_page_path = AGOO_ATOMIC_INT_INIT(0);
50
- atomic_int mem_page_slot = AGOO_ATOMIC_INT_INIT(0);
51
- atomic_int mem_pub = AGOO_ATOMIC_INT_INIT(0);
52
- atomic_int mem_qitem = AGOO_ATOMIC_INT_INIT(0);
53
- atomic_int mem_queue_item = AGOO_ATOMIC_INT_INIT(0);
54
- atomic_int mem_rack_logger = AGOO_ATOMIC_INT_INIT(0);
55
- atomic_int mem_req = AGOO_ATOMIC_INT_INIT(0);
56
- atomic_int mem_res = AGOO_ATOMIC_INT_INIT(0);
57
- atomic_int mem_res_body = AGOO_ATOMIC_INT_INIT(0);
58
- atomic_int mem_response = AGOO_ATOMIC_INT_INIT(0);
59
- atomic_int mem_subject = AGOO_ATOMIC_INT_INIT(0);
60
- atomic_int mem_text = AGOO_ATOMIC_INT_INIT(0);
61
- atomic_int mem_to_s = AGOO_ATOMIC_INT_INIT(0);
62
- atomic_int mem_upgraded = AGOO_ATOMIC_INT_INIT(0);
20
+ typedef struct _rep {
21
+ struct _rep *next;
22
+ size_t size;
23
+ const char *file;
24
+ int line;
25
+ int cnt;
26
+ } *Rep;
63
27
 
64
28
  #ifdef MEM_DEBUG
65
- static void
66
- print_stats() {
67
- Rec r;
68
29
 
69
- printf("********************************************************************************\n");
70
- pthread_mutex_lock(&lock);
71
-
72
- while (NULL != (r = recs)) {
73
- int cnt = 1;
74
- Rec prev = NULL;
75
- Rec next = NULL;
76
- Rec r2;
77
-
78
- recs = r->next;
79
- for (r2 = recs; NULL != r2; r2 = next) {
80
- next = r2->next;
81
- if (r->file == r2->file && r->line == r2->line) {
82
- cnt++;
83
- if (NULL == prev) {
84
- recs = r2->next;
85
- } else {
86
- prev->next = r2->next;
87
- }
88
- free(r2);
89
- } else {
90
- prev = r2;
91
- }
92
- }
93
- printf("%16s:%3d %-12s allocated and not freed %4d times.\n", r->file, r->line, r->type + 4, cnt);
94
- free(r);
95
- }
96
- pthread_mutex_unlock(&lock);
97
-
98
- printf("********************************************************************************\n");
99
- #if 0
100
- printf("memory statistics\n");
101
- printf(" mem_bind: %d\n", mem_bind);
102
- printf(" mem_cb: %d\n", mem_cb);
103
- printf(" mem_con: %d\n", mem_con);
104
- printf(" mem_cslot: %d\n", mem_cslot);
105
- printf(" mem_err_stream: %d\n", mem_err_stream);
106
- printf(" mem_eval_threads: %d\n", mem_eval_threads);
107
- printf(" mem_header: %d\n", mem_header);
108
- printf(" mem_hook: %d\n", mem_hook);
109
- printf(" mem_hook_pattern: %d\n", mem_hook_pattern);
110
- printf(" mem_http_slot: %d\n", mem_http_slot);
111
- printf(" mem_log_entry: %d\n", mem_log_entry);
112
- printf(" mem_log_what: %d\n", mem_log_what);
113
- printf(" mem_log_tid: %d\n", mem_log_tid);
114
- printf(" mem_mime_slot: %d\n", mem_mime_slot);
115
- printf(" mem_page: %d\n", mem_page);
116
- printf(" mem_page_msg: %d\n", mem_page_msg);
117
- printf(" mem_page_path: %d\n", mem_page_path);
118
- printf(" mem_page_slot: %d\n", mem_page_slot);
119
- printf(" mem_pub: %d\n", mem_pub);
120
- printf(" mem_qitem: %d\n", mem_qitem);
121
- printf(" mem_queue_item: %d\n", mem_queue_item);
122
- printf(" mem_rack_logger: %d\n", mem_rack_logger);
123
- printf(" mem_req: %d\n", mem_req);
124
- printf(" mem_res: %d\n", mem_res);
125
- printf(" mem_res_body: %d\n", mem_res_body);
126
- printf(" mem_response: %d\n", mem_response);
127
- printf(" mem_text: %d\n", mem_text);
128
- printf(" mem_to_s: %d\n", mem_to_s);
129
- #endif
130
- }
131
- #endif
132
-
133
- #if 0
134
- static void*
135
- handle_gc(void *x) {
136
- rb_gc_enable();
137
- rb_gc();
138
- return NULL;
139
- }
140
- #endif
30
+ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
31
+ static Rec recs = NULL;
32
+ static const char mem_pad[] = "--- This is a memory pad and should not change until being freed. ---";
141
33
 
142
34
  void
143
- debug_report() {
144
- #ifdef MEM_DEBUG
145
- // TBD how can ownership of GVL be determined?
146
- //rb_thread_call_with_gvl(handle_gc, NULL);
147
- print_stats();
148
- #endif
35
+ agoo_alloc(const void *ptr, size_t size, const char *file, int line) {
36
+ Rec r = (Rec)malloc(sizeof(struct _rec));
37
+
38
+ r->ptr = ptr;
39
+ r->size = size;
40
+ r->file = file;
41
+ r->line = line;
42
+ pthread_mutex_lock(&lock);
43
+ r->next = recs;
44
+ recs = r;
45
+ pthread_mutex_unlock(&lock);
149
46
  }
150
47
 
151
- void
152
- debug_rreport() {
153
- #ifdef MEM_DEBUG
154
- rb_gc_enable();
155
- rb_gc();
156
- print_stats();
157
- #endif
158
- }
48
+ void*
49
+ agoo_malloc(size_t size, const char *file, int line) {
50
+ void *ptr = malloc(size + sizeof(mem_pad));
51
+ Rec r = (Rec)malloc(sizeof(struct _rec));
159
52
 
160
- void
161
- debug_add(void *ptr, const char *type, const char *file, int line) {
162
- Rec r = (Rec)malloc(sizeof(struct _rec));
163
-
53
+ strcpy(((char*)ptr) + size, mem_pad);
164
54
  r->ptr = ptr;
165
- r->type = type;
55
+ r->size = size;
166
56
  r->file = file;
167
57
  r->line = line;
168
- pthread_mutex_lock(&lock);
58
+ pthread_mutex_lock(&lock);
169
59
  r->next = recs;
170
60
  recs = r;
171
- pthread_mutex_unlock(&lock);
61
+ pthread_mutex_unlock(&lock);
62
+
63
+ return ptr;
172
64
  }
173
65
 
174
- void
175
- debug_update(void *orig, void *ptr, const char *type, const char *file, int line) {
176
- Rec r;
66
+ void*
67
+ agoo_realloc(void *orig, size_t size, const char *file, int line) {
68
+ void *ptr = realloc(orig, size + sizeof(mem_pad));
69
+ Rec r;
177
70
 
71
+ strcpy(((char*)ptr) + size, mem_pad);
178
72
  pthread_mutex_lock(&lock);
179
73
  for (r = recs; NULL != r; r = r->next) {
180
74
  if (orig == r->ptr) {
181
75
  r->ptr = ptr;
76
+ r->size = size;
77
+ r->file = file;
78
+ r->line = line;
182
79
  break;
183
80
  }
184
81
  }
185
- pthread_mutex_unlock(&lock);
82
+ pthread_mutex_unlock(&lock);
186
83
  if (NULL == r) {
187
84
  printf("Realloc at %s:%d (%p) not allocated.\n", file, line, orig);
188
85
  }
86
+ return ptr;
87
+ }
88
+
89
+ char*
90
+ agoo_strdup(const char *str, const char *file, int line) {
91
+ size_t size = strlen(str) + 1;
92
+ char *ptr = (char*)malloc(size + sizeof(mem_pad));
93
+ Rec r = (Rec)malloc(sizeof(struct _rec));
94
+
95
+ strcpy(ptr, str);
96
+ strcpy(((char*)ptr) + size, mem_pad);
97
+ r->ptr = (void*)ptr;
98
+ r->size = size;
99
+ r->file = file;
100
+ r->line = line;
101
+ pthread_mutex_lock(&lock);
102
+ r->next = recs;
103
+ recs = r;
104
+ pthread_mutex_unlock(&lock);
105
+
106
+ return ptr;
107
+ }
108
+
109
+ char*
110
+ agoo_strndup(const char *str, size_t len, const char *file, int line) {
111
+ size_t size = len + 1;
112
+ char *ptr = (char*)malloc(size + sizeof(mem_pad));
113
+ Rec r = (Rec)malloc(sizeof(struct _rec));
114
+
115
+ memcpy(ptr, str, len);
116
+ ptr[len] = '\0';
117
+ strcpy(((char*)ptr) + size, mem_pad);
118
+ r->ptr = (void*)ptr;
119
+ r->size = size;
120
+ r->file = file;
121
+ r->line = line;
122
+ pthread_mutex_lock(&lock);
123
+ r->next = recs;
124
+ recs = r;
125
+ pthread_mutex_unlock(&lock);
126
+
127
+ return ptr;
128
+ }
129
+
130
+ void
131
+ agoo_mem_check(void *ptr, const char *file, int line) {
132
+ if (NULL != ptr) {
133
+ Rec r = NULL;
134
+
135
+ pthread_mutex_lock(&lock);
136
+ for (r = recs; NULL != r; r = r->next) {
137
+ if (ptr == r->ptr) {
138
+ break;
139
+ }
140
+ }
141
+ pthread_mutex_unlock(&lock);
142
+ if (NULL == r) {
143
+ printf("Memory check at %s:%d (%p) not allocated or already freed.\n", file, line, ptr);
144
+ } else {
145
+ char *pad = (char*)r->ptr + r->size;
146
+
147
+ if (0 != strcmp(mem_pad, pad)) {
148
+ uint8_t *p;
149
+ uint8_t *end = (uint8_t*)pad + sizeof(mem_pad);
150
+
151
+ printf("Check - Memory at %s:%d (%p) write outside allocated.\n", file, line, ptr);
152
+ for (p = (uint8_t*)pad; p < end; p++) {
153
+ if (0x20 < *p && *p < 0x7f) {
154
+ printf("%c ", *p);
155
+ } else {
156
+ printf("%02x ", *(uint8_t*)p);
157
+ }
158
+ }
159
+ printf("\n");
160
+ }
161
+ }
162
+ }
189
163
  }
190
164
 
191
165
  void
192
- debug_del(void *ptr, const char *file, int line) {
193
- Rec r = NULL;
194
- Rec prev = NULL;
166
+ agoo_freed(void *ptr, const char *file, int line) {
167
+ if (NULL != ptr) {
168
+ Rec r = NULL;
169
+ Rec prev = NULL;
195
170
 
196
- pthread_mutex_lock(&lock);
197
- for (r = recs; NULL != r; r = r->next) {
198
- if (ptr == r->ptr) {
199
- if (NULL == prev) {
200
- recs = r->next;
201
- } else {
202
- prev->next = r->next;
171
+ pthread_mutex_lock(&lock);
172
+ for (r = recs; NULL != r; r = r->next) {
173
+ if (ptr == r->ptr) {
174
+ if (NULL == prev) {
175
+ recs = r->next;
176
+ } else {
177
+ prev->next = r->next;
178
+ }
179
+ break;
203
180
  }
181
+ prev = r;
182
+ }
183
+ pthread_mutex_unlock(&lock);
184
+ if (NULL == r) {
185
+ printf("Free at %s:%d (%p) not allocated or already freed.\n", file, line, ptr);
186
+ } else {
187
+ char *pad = (char*)r->ptr + r->size;
188
+
189
+ if (0 != strcmp(mem_pad, pad)) {
190
+ uint8_t *p;
191
+ uint8_t *end = (uint8_t*)pad + sizeof(mem_pad);
192
+
193
+ printf("Memory at %s:%d (%p) write outside allocated.\n", file, line, ptr);
194
+ for (p = (uint8_t*)pad; p < end; p++) {
195
+ if (0x20 < *p && *p < 0x7f) {
196
+ printf("%c ", *p);
197
+ } else {
198
+ printf("%02x ", *(uint8_t*)p);
199
+ }
200
+ }
201
+ printf("\n");
202
+ }
203
+ free(r);
204
+ }
205
+ }
206
+ }
207
+
208
+ void
209
+ agoo_free(void *ptr, const char *file, int line) {
210
+ if (NULL != ptr) {
211
+ agoo_freed(ptr, file, line);
212
+ free(ptr);
213
+ }
214
+ }
215
+
216
+ #endif
217
+
218
+ #ifdef MEM_DEBUG
219
+
220
+ static Rep
221
+ update_reps(Rep reps, Rec r) {
222
+ Rep rp = reps;
223
+
224
+ for (; NULL != rp; rp = rp->next) {
225
+ if (rp->line == r->line && (rp->file == r->file || 0 == strcmp(rp->file, r->file))) {
226
+ rp->size += r->size;
227
+ rp->cnt++;
204
228
  break;
205
229
  }
206
- prev = r;
207
230
  }
208
- pthread_mutex_unlock(&lock);
209
- if (NULL == r) {
210
- printf("Free at %s:%d (%p) not allocated or already freed.\n", file, line, ptr);
231
+ if (NULL == rp) {
232
+ rp = (Rep)malloc(sizeof(struct _rep));
233
+ rp->size = r->size;
234
+ rp->file = r->file;
235
+ rp->line = r->line;
236
+ rp->cnt = 1;
237
+ rp->next = reps;
238
+ reps = rp;
239
+ }
240
+ return reps;
241
+ }
242
+
243
+ static void
244
+ print_stats() {
245
+ printf("\n--- Memory Usage Report --------------------------------------------------------\n");
246
+ pthread_mutex_lock(&lock);
247
+
248
+ if (NULL == recs) {
249
+ printf("No memory leaks\n");
211
250
  } else {
212
- free(r);
251
+ Rep reps = NULL;
252
+ Rep rp;
253
+ Rec r;
254
+ size_t leaked = 0;
255
+
256
+ for (r = recs; NULL != r; r = r->next) {
257
+ reps = update_reps(reps, r);
258
+ }
259
+ while (NULL != (rp = reps)) {
260
+ reps = rp->next;
261
+ printf("%16s:%3d %8lu bytes over %d occurances allocated and not freed.\n", rp->file, rp->line, rp->size, rp->cnt);
262
+ leaked += rp->size;
263
+ free(rp);
264
+ }
265
+ printf("%lu bytes leaked\n", leaked);
213
266
  }
267
+ pthread_mutex_unlock(&lock);
268
+ printf("--------------------------------------------------------------------------------\n");
269
+ }
270
+ #endif
271
+
272
+ void
273
+ debug_report() {
274
+ #ifdef MEM_DEBUG
275
+ print_stats();
276
+ #endif
214
277
  }