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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +38 -0
- data/ext/agoo/agoo.c +11 -2
- data/ext/agoo/bind.c +15 -20
- data/ext/agoo/con.c +32 -25
- data/ext/agoo/debug.c +225 -162
- data/ext/agoo/debug.h +31 -51
- data/ext/agoo/doc.c +278 -5
- data/ext/agoo/doc.h +6 -1
- data/ext/agoo/err.c +1 -0
- data/ext/agoo/err.h +1 -0
- data/ext/agoo/error_stream.c +3 -6
- data/ext/agoo/gqlcobj.c +12 -0
- data/ext/agoo/gqlcobj.h +25 -0
- data/ext/agoo/gqleval.c +520 -0
- data/ext/agoo/gqleval.h +49 -0
- data/ext/agoo/gqlintro.c +1237 -97
- data/ext/agoo/gqlintro.h +8 -0
- data/ext/agoo/gqljson.c +460 -0
- data/ext/agoo/gqljson.h +15 -0
- data/ext/agoo/gqlvalue.c +679 -136
- data/ext/agoo/gqlvalue.h +29 -7
- data/ext/agoo/graphql.c +841 -362
- data/ext/agoo/graphql.h +180 -90
- data/ext/agoo/hook.c +8 -16
- data/ext/agoo/http.c +3 -4
- data/ext/agoo/log.c +22 -25
- data/ext/agoo/log.h +1 -0
- data/ext/agoo/page.c +24 -40
- data/ext/agoo/pub.c +23 -21
- data/ext/agoo/queue.c +2 -4
- data/ext/agoo/ready.c +9 -9
- data/ext/agoo/req.c +80 -5
- data/ext/agoo/req.h +2 -0
- data/ext/agoo/res.c +1 -3
- data/ext/agoo/rgraphql.c +753 -0
- data/ext/agoo/rresponse.c +9 -15
- data/ext/agoo/rserver.c +18 -17
- data/ext/agoo/sdl.c +1264 -120
- data/ext/agoo/sdl.h +8 -1
- data/ext/agoo/sectime.c +136 -0
- data/ext/agoo/sectime.h +19 -0
- data/ext/agoo/server.c +1 -3
- data/ext/agoo/subject.c +2 -4
- data/ext/agoo/text.c +124 -18
- data/ext/agoo/text.h +5 -1
- data/ext/agoo/upgraded.c +2 -4
- data/lib/agoo/version.rb +1 -1
- data/test/base_handler_test.rb +43 -40
- data/test/bind_test.rb +49 -48
- data/test/graphql_test.rb +1019 -0
- data/test/hijack_test.rb +1 -1
- data/test/rack_handler_test.rb +40 -34
- data/test/static_test.rb +33 -32
- metadata +17 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2777518b8ae392fd175eb2a70e10ddc88698c8a1a7c2435fb02a210017d401ad
|
4
|
+
data.tar.gz: c2020e0aeca0163470c3501a0f718df32170039520d117d1b1a5b939f68840b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e60ec30b4b6f0ce6f8a5b98faf79ca5facd28bd435be0f91ebbfcf0f9ba8678e79f6fa279cc8ab7ad38b1eec99c7c76d9f171c46e377646dd9ad25df22d6c937
|
7
|
+
data.tar.gz: 565408d7edf87f3d6d3f26534447c98c3cd4dc545685576d36252684885e23e05c097579318dfc9b2ab6ff23fbfda5868383374c6f97b0f88b599f5e488aee25
|
data/CHANGELOG.md
CHANGED
@@ -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
|
data/ext/agoo/agoo.c
CHANGED
@@ -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
|
-
|
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);
|
data/ext/agoo/bind.c
CHANGED
@@ -15,18 +15,17 @@
|
|
15
15
|
|
16
16
|
agooBind
|
17
17
|
agoo_bind_port(agooErr err, int port) {
|
18
|
-
agooBind b = (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 =
|
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)
|
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 =
|
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)
|
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 =
|
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)
|
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 =
|
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 =
|
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
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
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
|
data/ext/agoo/con.c
CHANGED
@@ -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)
|
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
|
-
|
95
|
-
|
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
|
-
|
939
|
-
|
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
|
-
|
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)
|
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
|
-
|
1233
|
-
free(res);
|
1240
|
+
AGOO_FREE(res);
|
1234
1241
|
}
|
1235
|
-
|
1242
|
+
AGOO_FREE(loop);
|
1236
1243
|
}
|
data/ext/agoo/debug.c
CHANGED
@@ -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
|
-
|
14
|
+
const void *ptr;
|
15
|
+
size_t size;
|
17
16
|
const char *file;
|
18
17
|
int line;
|
19
18
|
} *Rec;
|
20
19
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
70
|
-
|
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
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
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
|
-
|
153
|
-
|
154
|
-
|
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
|
-
|
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->
|
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
|
-
|
176
|
-
|
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
|
-
|
193
|
-
|
194
|
-
|
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
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
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
|
-
|
209
|
-
|
210
|
-
|
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
|
-
|
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
|
}
|