 src/cuda_control.c |  24 +-------
 src/gpuscan.c      | 167 ++++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 148 insertions(+), 43 deletions(-)

diff --git a/src/cuda_control.c b/src/cuda_control.c
index 4d29591..de5e3a3 100644
--- a/src/cuda_control.c
+++ b/src/cuda_control.c
@@ -1372,7 +1372,7 @@ launch_pending_tasks(GpuTaskState *gts)
  *
  */
 static bool
-__waitfor_ready_tasks(GpuTaskState *gts)
+waitfor_ready_tasks(GpuTaskState *gts)
 {
 	bool	retry_next = true;
 	bool	wait_latch = true;
@@ -1459,28 +1459,6 @@ __waitfor_ready_tasks(GpuTaskState *gts)
 	return retry_next;
 }
 
-static bool
-waitfor_ready_tasks(GpuTaskState *gts)
-{
-	bool	save_set_latch_on_sigusr1 = set_latch_on_sigusr1;
-	bool	status;
-
-	set_latch_on_sigusr1 = true;
-	PG_TRY();
-	{
-		status = __waitfor_ready_tasks(gts);
-	}
-	PG_CATCH();
-	{
-		set_latch_on_sigusr1 = save_set_latch_on_sigusr1;
-		PG_RE_THROW();
-	}
-	PG_END_TRY();
-	set_latch_on_sigusr1 = save_set_latch_on_sigusr1;
-
-	return status;
-}
-
 /*
  * gpucontext_health_check
  *
diff --git a/src/gpuscan.c b/src/gpuscan.c
index 7fb11a7..5a8e633 100644
--- a/src/gpuscan.c
+++ b/src/gpuscan.c
@@ -19,6 +19,7 @@
 #include "access/xact.h"
 #include "catalog/pg_namespace.h"
 #include "miscadmin.h"
+#include "nodes/readfuncs.h"
 #include "optimizer/cost.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
@@ -35,9 +36,9 @@
 
 static set_rel_pathlist_hook_type	set_rel_pathlist_next;
 static CustomPathMethods		gpuscan_path_methods;
-static CustomScanMethods		gpuscan_plan_methods;
+CustomScanMethods				gpuscan_plan_methods;
 static PGStromExecMethods		gpuscan_exec_methods;
-static CustomScanMethods		bulkscan_plan_methods;
+CustomScanMethods				bulkscan_plan_methods;
 static PGStromExecMethods		bulkscan_exec_methods;
 static bool						enable_gpuscan;
 
@@ -61,6 +62,15 @@ typedef struct {
 	List	   *dev_quals;		/* qualifiers to be run on device */
 } GpuScanInfo;
 
+typedef struct {
+	CustomScan	cscan;
+	char	   *kern_source;
+	int32		extra_flags;
+	List	   *used_params;
+	List	   *used_vars;
+	List	   *dev_quals;
+} GpuScanPlan;
+
 static inline void
 form_gpuscan_info(CustomScan *cscan, GpuScanInfo *gscan_info)
 {
@@ -502,7 +512,7 @@ create_gpuscan_plan(PlannerInfo *root,
 					List *clauses,
 					List *custom_children)
 {
-	CustomScan	   *cscan;
+	GpuScanPlan	   *gscan;
 	GpuScanInfo		gs_info;
 	List		   *host_quals = NIL;
 	List		   *dev_quals = NIL;
@@ -543,23 +553,29 @@ create_gpuscan_plan(PlannerInfo *root,
 	/*
 	 * Construction of GpuScanPlan node; on top of CustomPlan node
 	 */
-	cscan = makeNode(CustomScan);
-	cscan->scan.plan.targetlist = tlist;
-	cscan->scan.plan.qual = host_quals;
-	cscan->scan.plan.lefttree = NULL;
-	cscan->scan.plan.righttree = NULL;
-	cscan->scan.scanrelid = rel->relid;
-
-	gs_info.kern_source = kern_source;
-	gs_info.extra_flags = context.extra_flags | DEVKERNEL_NEEDS_GPUSCAN;
-	gs_info.used_params = context.used_params;
-	gs_info.used_vars = context.used_vars;
-	gs_info.dev_quals = dev_quals;
-	form_gpuscan_info(cscan, &gs_info);
-	cscan->flags = best_path->flags;
-	cscan->methods = &gpuscan_plan_methods;
-
-	return &cscan->scan.plan;
+	gscan = palloc0(sizeof(GpuScanPlan));
+	NodeSetTag(gscan, T_CustomScan);
+
+	gscan->cscan.scan.plan.targetlist = tlist;
+	gscan->cscan.scan.plan.qual = host_quals;
+	gscan->cscan.scan.plan.lefttree = NULL;
+	gscan->cscan.scan.plan.righttree = NULL;
+	gscan->cscan.scan.scanrelid = rel->relid;
+	gscan->kern_source = kern_source;
+	gscan->extra_flags = context.extra_flags | DEVKERNEL_NEEDS_GPUSCAN;
+	gscan->used_vars = context.used_vars;
+	gscan->dev_quals = dev_quals;
+	gscan->cscan.flags = best_path->flags;
+	gscan->cscan.methods = &gpuscan_plan_methods;
+
+	gs_info.kern_source = gscan->kern_source;
+	gs_info.extra_flags = gscan->extra_flags;
+	gs_info.used_params = gscan->used_params;
+	gs_info.used_vars = gscan->used_vars;
+	gs_info.dev_quals = gscan->dev_quals;
+	form_gpuscan_info(&gscan->cscan, &gs_info);
+
+	return &gscan->cscan.scan.plan;
 }
 
 /*
@@ -639,6 +655,100 @@ gpuscan_create_scan_state(CustomScan *cscan)
 	return (Node *) gss;
 }
 
+/* copy and paste from outfuncs.c */
+static void
+_outToken(StringInfo str, const char *s)
+{
+	if (s == NULL || *s == '\0')
+	{
+		appendStringInfoString(str, "<>");
+		return;
+	}
+
+	/*
+	 * Look for characters or patterns that are treated specially by read.c
+	 * (either in pg_strtok() or in nodeRead()), and therefore need a
+	 * protective backslash.
+	 */
+	/* These characters only need to be quoted at the start of the string */
+	if (*s == '<' ||
+		*s == '\"' ||
+		isdigit((unsigned char) *s) ||
+		((*s == '+' || *s == '-') &&
+		 (isdigit((unsigned char) s[1]) || s[1] == '.')))
+		appendStringInfoChar(str, '\\');
+	while (*s)
+	{
+		/* These chars must be backslashed anywhere in the string */
+		if (*s == ' ' || *s == '\n' || *s == '\t' ||
+			*s == '(' || *s == ')' || *s == '{' || *s == '}' ||
+			*s == '\\')
+			appendStringInfoChar(str, '\\');
+		appendStringInfoChar(str, *s++);
+	}
+}
+
+static void
+gpuscan_textout(StringInfo str, const CustomScan *node)
+{
+	GpuScanPlan	   *gscan = (GpuScanPlan *) node;
+
+	appendStringInfo(str, " :kern_source ");
+	_outToken(str, gscan->kern_source);
+	appendStringInfo(str, " :extra_flags %u", gscan->extra_flags);
+	appendStringInfo(str, " :used_params %s",
+					 nodeToString(gscan->used_params));
+	appendStringInfo(str, " :used_vars %s",
+					 nodeToString(gscan->used_vars));
+	appendStringInfo(str, " :dev_quals %s",
+					 nodeToString(gscan->dev_quals));
+}
+
+static CustomScan *
+gpuscan_textread(void)
+{
+	GpuScanPlan	   *gscan = palloc0(sizeof(GpuScanPlan));
+	char		   *token;
+	int				length;
+
+	NodeSetTag(gscan, T_CustomScan);
+	/* kern_source */
+	token = pg_strtok(&length);
+	token = pg_strtok(&length);
+	gscan->kern_source = (length > 0 ? debackslash(token, length) : NULL);
+	/* extra_flags */
+	token = pg_strtok(&length);
+	token = pg_strtok(&length);
+	gscan->extra_flags = (cl_uint)strtoul(token, NULL, 10);
+	/* used_params */
+	token = pg_strtok(&length);
+	gscan->used_params = nodeRead(NULL, 0);
+	/* used_vars */
+	token = pg_strtok(&length);
+	gscan->used_vars = nodeRead(NULL, 0);
+	/* dev_quals */
+	token = pg_strtok(&length);
+	gscan->dev_quals = nodeRead(NULL, 0);
+
+	return &gscan->cscan;
+}
+
+static CustomScan *
+gpuscan_nodecopy(const CustomScan *__from)
+{
+	GpuScanPlan	   *from = (GpuScanPlan *) __from;
+	GpuScanPlan	   *to = palloc0(sizeof(GpuScanPlan));
+
+	NodeSetTag(to, T_CustomScan);
+	to->kern_source = (from->kern_source ? pstrdup(from->kern_source) : NULL);
+	to->extra_flags = from->extra_flags;
+	to->used_params = copyObject(from->used_params);
+	to->used_vars = copyObject(from->used_vars);
+	to->dev_quals = copyObject(from->dev_quals);
+
+	return &to->cscan;
+}
+
 static void
 gpuscan_begin(CustomScanState *node, EState *estate, int eflags)
 {
@@ -646,6 +756,15 @@ gpuscan_begin(CustomScanState *node, EState *estate, int eflags)
 	GpuContext	   *gcontext = NULL;
 	GpuScanState   *gss = (GpuScanState *) node;
 	GpuScanInfo	   *gs_info = deform_gpuscan_info(node->ss.ps.plan);
+	CustomScan	   *dplan;
+	char		   *str_1;
+	char		   *str_2;
+
+	dplan = stringToNode(nodeToString(copyObject(node->ss.ps.plan)));
+	str_1 = nodeToString(node->ss.ps.plan);
+	str_2 = nodeToString(dplan);
+	elog(INFO, "str_1 => %s", str_1);
+	elog(INFO, "str_2 => %s", str_2);
 
 	/* gpuscan should not have inner/outer plan right now */
 	Assert(outerPlan(node) == NULL);
@@ -969,10 +1088,18 @@ pgstrom_init_gpuscan(void)
 	memset(&gpuscan_plan_methods, 0, sizeof(gpuscan_plan_methods));
 	gpuscan_plan_methods.CustomName			= "GpuScan";
 	gpuscan_plan_methods.CreateCustomScanState = gpuscan_create_scan_state;
+	gpuscan_plan_methods.TextOutCustomScan	= gpuscan_textout;
+	gpuscan_plan_methods.TextReadCustomScan	= gpuscan_textread;
+	gpuscan_plan_methods.NodeCopyCustomScan	= gpuscan_nodecopy;
+	INIT_CUSTOM_SCAN_METHODS(gpuscan_plan_methods, "GpuScan");
 
 	memset(&bulkscan_plan_methods, 0, sizeof(bulkscan_plan_methods));
 	bulkscan_plan_methods.CustomName		= "BulkScan";
 	bulkscan_plan_methods.CreateCustomScanState = gpuscan_create_scan_state;
+	bulkscan_plan_methods.TextOutCustomScan	= gpuscan_textout;
+	bulkscan_plan_methods.TextReadCustomScan= gpuscan_textread;
+	bulkscan_plan_methods.NodeCopyCustomScan= gpuscan_nodecopy;
+	INIT_CUSTOM_SCAN_METHODS(bulkscan_plan_methods, "GpuScan");
 
 	/* setup exec methods */
 	memset(&gpuscan_exec_methods, 0, sizeof(gpuscan_exec_methods));
