1 module grpc.common.call; 2 import grpc.logger; 3 import interop.headers; 4 import grpc.common.cq; 5 import grpc.core.utils; 6 import grpc.core.resource; 7 import grpc.common.metadata; 8 import grpc.common.byte_buffer; 9 import grpc.core.sync.mutex; 10 import core.memory : GC; 11 import core.lifetime; 12 13 struct CallContext { 14 @safe @nogc: 15 shared(Mutex) mutex; 16 grpc_call** call; 17 CallDetails details; 18 MetadataArray metadata; 19 ByteBuffer data; 20 MonoTime timestamp; 21 22 static CallContext create() @trusted { 23 auto call = cast(grpc_call**)gpr_zalloc((grpc_call**).sizeof); 24 return CallContext(cast(shared)Mutex.create(), 25 call, 26 CallDetails.create(), 27 MetadataArray.create(), 28 ByteBuffer.create()); 29 } 30 31 @disable this(this); 32 33 ~this() @trusted { 34 destroy(data); 35 gpr_free(cast(void*)call); 36 } 37 } 38 39 struct CallDetails { 40 @safe @nogc: 41 private { 42 shared(Mutex) mutex; 43 SharedResource _details; 44 } 45 46 inout(grpc_call_details)* handle() inout @trusted nothrow { 47 return cast(typeof(return)) _details.handle; 48 } 49 50 @property string method() @trusted { 51 mutex.lock; 52 scope(exit) mutex.unlock; 53 return slice_to_string(handle.method); 54 } 55 56 @property string host() @trusted { 57 mutex.lock; 58 scope(exit) mutex.unlock; 59 return slice_to_string(handle.host); 60 } 61 62 @property uint flags() { 63 mutex.lock; 64 scope(exit) mutex.unlock; 65 uint flags = handle.flags; 66 return flags; 67 } 68 69 @property Duration deadline() @trusted { 70 mutex.lock; 71 scope(exit) mutex.unlock; 72 Duration d = timespectodur(handle.deadline); 73 return d; 74 } 75 76 static CallDetails create() @trusted { 77 grpc_call_details* details; 78 79 if ((details = cast(grpc_call_details*)gpr_zalloc((grpc_call_details).sizeof)) != null) { 80 static bool release(shared(void)* ptr) @trusted nothrow { 81 grpc_call_details_destroy(cast(grpc_call_details*)ptr); 82 gpr_free(cast(void*)ptr); 83 return true; 84 } 85 86 grpc_call_details_init(details); 87 CallDetails obj = CallDetails(cast(shared)Mutex.create(), SharedResource(cast(shared)details, &release)); 88 return obj; 89 } else { 90 assert(0, "memory allocation failed"); 91 } 92 93 } 94 95 ~this() @trusted { 96 destroy(_details); 97 } 98 99 100 @disable this(this); 101 } 102 103 // since we handle the memory for the CQ tags manually (and since there should only ever be very few tags) 104 // which actually exist, this should be never cleaned up by the garbage collector as it contains VERY important 105 // things 106 107 struct Tag { 108 @safe @nogc: 109 void* method; 110 string methodName; 111 ubyte[16] metadata; 112 CallContext ctx; 113 114 static Tag* opCall() @trusted { 115 Tag* obj = cast(Tag*)gpr_zalloc((Tag).sizeof); 116 DEBUG!"new tag created at: %x size: %d"(obj, (Tag).sizeof); 117 assert(obj != null, "memory allocation fail"); 118 obj.ctx = CallContext.create(); 119 return obj; 120 } 121 122 static void free(Tag* tag) @trusted { 123 destroy(tag.ctx); 124 gpr_free(tag); 125 } 126 127 ~this() { 128 assert(0); // the tag should NEVER have it's destructor called, you MUST call free on it 129 } 130 131 132 @disable this(this); 133 }