Introduce wr_list support
diff --git a/include/env.h b/include/env.h
index e82f5a4..dc76b43 100644
--- a/include/env.h
+++ b/include/env.h
@@ -339,6 +339,9 @@
 	char meminfo[8192];
 	int ram_init;
 
+	struct ibv_send_wr *wr_list;
+	struct ibv_send_wr *wr_list_end;
+
 	void init_ram() {
 		int fd = open("/proc/meminfo", O_RDONLY);
 		ASSERT_GT(fd, 0);
@@ -359,6 +362,22 @@
 		}
 	}
 
+	virtual void add_wr(ibv_send_wr *wr) {
+		if (wr_list)
+			wr_list_end->next = wr;
+		else
+			wr_list = wr;
+		wr_list_end = wr;
+	}
+
+	virtual void free_wr() {
+		while (wr_list) {
+			struct ibv_send_wr *wr = wr_list;
+			wr_list = wr_list->next;
+			free(wr);
+		}
+	}
+
 	ibvt_env() :
 		env(*this),
 		lvl(0),
@@ -366,7 +385,8 @@
 		fatality(0),
 		flags(ACTIVE),
 		run(0),
-		ram_init(0)
+		ram_init(0),
+		wr_list(NULL)
 	{
 		memset(lvl_str, 0, sizeof(lvl_str));
 	}
@@ -922,6 +942,12 @@
 		SET(qp, ibv_create_qp_ex(pd.ctx.ctx, &attr));
 	}
 
+	virtual void post_all_wr() {
+		struct ibv_send_wr *bad_wr = NULL;
+		DO(ibv_post_send(qp, env.wr_list, &bad_wr));
+		env.free_wr();
+	}
+
 	virtual void recv(ibv_sge sge) {
 		struct ibv_recv_wr wr;
 		struct ibv_recv_wr *bad_wr = NULL;
@@ -949,22 +975,28 @@
 		DO(ibv_post_send(qp, &wr, &bad_wr));
 	}
 
-	virtual void rdma(ibv_sge src_sge, ibv_sge dst_sge, enum ibv_wr_opcode opcode, enum ibv_send_flags flags = IBV_SEND_SIGNALED) {
-		struct ibv_send_wr wr;
-		struct ibv_send_wr *bad_wr = NULL;
+	virtual void rdma_wr(ibv_sge src_sge, ibv_sge dst_sge, enum ibv_wr_opcode opcode, int flags = IBV_SEND_SIGNALED) {
+		struct __rdma_wr {
+			ibv_send_wr wr;
+			ibv_sge sge;
+		} *wr = (__rdma_wr *)calloc(1, sizeof(*wr));
 
-		memset(&wr, 0, sizeof(wr));
-		wr.next = NULL;
-		wr.wr_id = 0;
-		wr.sg_list = &src_sge;
-		wr.num_sge = 1;
-		wr._wr_opcode = opcode;
-		wr._wr_send_flags = flags;
+		wr->sge = src_sge;
+		wr->wr.wr_id = 0;
+		wr->wr.sg_list = &wr->sge;
+		wr->wr.num_sge = 1;
+		wr->wr._wr_opcode = opcode;
+		wr->wr._wr_send_flags = flags;
 
-		wr.wr.rdma.remote_addr = dst_sge.addr;
-		wr.wr.rdma.rkey = dst_sge.lkey;
+		wr->wr.wr.rdma.remote_addr = dst_sge.addr;
+		wr->wr.wr.rdma.rkey = dst_sge.lkey;
 
-		DO(ibv_post_send(qp, &wr, &bad_wr));
+		env.add_wr(&wr->wr);
+	}
+
+	virtual void rdma(ibv_sge src_sge, ibv_sge dst_sge, enum ibv_wr_opcode opcode, int flags = IBV_SEND_SIGNALED) {
+		rdma_wr(src_sge, dst_sge, opcode, flags);
+		EXEC(post_all_wr());
 	}
 
 	virtual void rdma2(ibv_sge src_sge1,
diff --git a/tests/sig-handover/smoke.cc b/tests/sig-handover/smoke.cc
index 89a1be2..c4e7a04 100644
--- a/tests/sig-handover/smoke.cc
+++ b/tests/sig-handover/smoke.cc
@@ -253,42 +253,59 @@
 		mw(mid_mr, 0, SZD(this->pi_size()), send_qp)
 	{ }
 
+	virtual void config_wr(ibvt_mr &sig_mr, struct ibv_sge data,
+			    struct ibv_exp_sig_domain mem,
+			    struct ibv_exp_sig_domain wire) {
+		struct __cfg_wr {
+			ibv_send_wr wr;
+			ibv_exp_sig_attrs sig;
+			ibv_sge data;
+		} *wr = (__cfg_wr *)calloc(1, sizeof(*wr));
+
+		wr->sig.check_mask = this->check_mask();
+		wr->sig.mem = mem;
+		wr->sig.wire = wire;
+
+		wr->data = data;
+
+		wr->wr.exp_opcode = IBV_EXP_WR_REG_SIG_MR;
+		wr->wr.exp_send_flags = IBV_EXP_SEND_SOLICITED;
+		wr->wr.ext_op.sig_handover.sig_attrs = &wr->sig;
+		wr->wr.ext_op.sig_handover.sig_mr = sig_mr.mr;
+		wr->wr.ext_op.sig_handover.access_flags =
+			IBV_ACCESS_LOCAL_WRITE |
+			IBV_ACCESS_REMOTE_READ |
+			IBV_ACCESS_REMOTE_WRITE;
+		wr->wr.ext_op.sig_handover.prot = NULL;
+
+		wr->wr.num_sge = 1;
+		wr->wr.sg_list = &wr->data;
+
+		add_wr(&wr->wr);
+	}
+
 	virtual void config(ibvt_mr &sig_mr, struct ibv_sge data,
 			    struct ibv_exp_sig_domain mem,
 			    struct ibv_exp_sig_domain wire) {
-		struct ibv_send_wr wr = {};
-		struct ibv_send_wr *bad_wr;
-		struct ibv_exp_sig_attrs sig = {};
+		config_wr(sig_mr, data, mem, wire);
+		EXEC(send_qp.post_all_wr());
+	}
 
-		sig.check_mask = this->check_mask();
-		sig.mem = mem;
-		sig.wire = wire;
+	virtual void linv_wr(ibvt_mr &sig_mr, int sign = 0) {
+		struct ibv_send_wr *wr = (ibv_send_wr *)calloc(1, sizeof(*wr));
 
-		wr.exp_opcode = IBV_EXP_WR_REG_SIG_MR;
-		wr.exp_send_flags = IBV_EXP_SEND_SIGNALED;
-		wr.ext_op.sig_handover.sig_attrs = &sig;
-		wr.ext_op.sig_handover.sig_mr = sig_mr.mr;
-		wr.ext_op.sig_handover.access_flags = IBV_ACCESS_LOCAL_WRITE |
-						      IBV_ACCESS_REMOTE_READ |
-						      IBV_ACCESS_REMOTE_WRITE;
-		wr.ext_op.sig_handover.prot = NULL;
+		wr->exp_opcode = IBV_EXP_WR_LOCAL_INV;
+		wr->exp_send_flags = IBV_EXP_SEND_SOLICITED | IBV_EXP_SEND_FENCE;
+		if (sign)
+			wr->exp_send_flags |= IBV_EXP_SEND_SIGNALED;
+		wr->ex.invalidate_rkey = sig_mr.mr->rkey;
 
-		wr.num_sge = 1;
-		wr.sg_list = &data;
-
-		DO(ibv_post_send(send_qp.qp, &wr, &bad_wr));
-		EXEC(cq.poll());
+		add_wr(wr);
 	}
 
 	virtual void linv(ibvt_mr &sig_mr) {
-		struct ibv_send_wr wr = {};
-		struct ibv_send_wr *bad_wr;
-
-		wr.exp_opcode = IBV_EXP_WR_LOCAL_INV;
-		wr.exp_send_flags = IBV_EXP_SEND_SIGNALED;
-		wr.ex.invalidate_rkey = sig_mr.mr->rkey;
-		DO(ibv_post_send(send_qp.qp, &wr, &bad_wr));
-		EXEC(cq.poll());
+		linv_wr(sig_mr);
+		EXEC(send_qp.post_all_wr());
 	}
 
 	void mr_status(ibvt_mr &mr, int expected) {