1 /**************************************************************************
5 Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
7 Contact: Eunchul Kim <chulspro.kim@samsung.com>,
8 JinYoung Jeon <jy0.jeon@samsung.com>,
9 Taeheon Kim <th908.kim@samsung.com>,
10 YoungJun Cho <yj44.cho@samsung.com>,
11 SooChan Lim <sc1.lim@samsung.com>,
12 Boram Park <sc1.lim@samsung.com>
14 Permission is hereby granted, free of charge, to any person obtaining a
15 copy of this software and associated documentation files (the
16 "Software"), to deal in the Software without restriction, including
17 without limitation the rights to use, copy, modify, merge, publish,
18 distribute, sub license, and/or sell copies of the Software, and to
19 permit persons to whom the Software is furnished to do so, subject to
20 the following conditions:
22 The above copyright notice and this permission notice (including the
23 next paragraph) shall be included in all copies or substantial portions
26 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
29 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
30 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
31 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
32 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 **************************************************************************/
41 #include "tdm_backend.h"
42 #include "tdm_private.h"
44 static tdm_private_layer*
45 _tdm_display_find_private_layer(tdm_private_output *private_output, tdm_layer *layer_backend)
47 tdm_private_layer *private_layer = NULL;
49 LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link)
51 if (private_layer->layer_backend == layer_backend)
58 static tdm_private_output*
59 _tdm_display_find_private_output(tdm_private_display *private_display, tdm_output *output_backend)
61 tdm_private_output *private_output = NULL;
63 LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link)
65 if (private_output->output_backend == output_backend)
66 return private_output;
73 _tdm_display_destroy_caps_pp(tdm_caps_pp *caps_pp)
75 free(caps_pp->formats);
76 memset(caps_pp, 0, sizeof(tdm_caps_pp));
80 _tdm_display_destroy_caps_capture(tdm_caps_capture *caps_capture)
82 free(caps_capture->formats);
83 memset(caps_capture, 0, sizeof(tdm_caps_capture));
87 _tdm_display_destroy_caps_layer(tdm_caps_layer *caps_layer)
89 free(caps_layer->formats);
90 free(caps_layer->props);
91 memset(caps_layer, 0, sizeof(tdm_caps_layer));
95 _tdm_display_destroy_caps_output(tdm_caps_output *caps_output)
97 free(caps_output->modes);
98 free(caps_output->props);
99 memset(caps_output, 0, sizeof(tdm_caps_output));
103 _tdm_display_destroy_private_layer(tdm_private_layer *private_layer)
105 tdm_private_capture *c = NULL, *cc = NULL;
107 LIST_DEL(&private_layer->link);
109 LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_layer->capture_list, link)
110 tdm_capture_destroy_internal(c);
112 _tdm_display_destroy_caps_layer(&private_layer->caps);
118 _tdm_display_destroy_private_output(tdm_private_output *private_output)
120 tdm_private_layer *l = NULL, *ll = NULL;
121 tdm_private_capture *c = NULL, *cc = NULL;
122 tdm_private_vblank_handler *v = NULL, *vv = NULL;
123 tdm_private_commit_handler *m = NULL, *mm = NULL;
125 LIST_DEL(&private_output->link);
127 free(private_output->layers_ptr);
129 LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_handler_list, link)
135 LIST_FOR_EACH_ENTRY_SAFE(m, mm, &private_output->commit_handler_list, link)
141 LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_output->capture_list, link)
142 tdm_capture_destroy_internal(c);
144 LIST_FOR_EACH_ENTRY_SAFE(l, ll, &private_output->layer_list, link)
145 _tdm_display_destroy_private_layer(l);
147 _tdm_display_destroy_caps_output(&private_output->caps);
149 free(private_output);
153 _tdm_display_destroy_private_display(tdm_private_display *private_display)
155 tdm_private_output *o = NULL, *oo = NULL;
156 tdm_private_pp *p = NULL, *pp = NULL;
158 free(private_display->outputs_ptr);
160 LIST_FOR_EACH_ENTRY_SAFE(p, pp, &private_display->pp_list, link)
161 tdm_pp_destroy_internal(p);
163 LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_display->output_list, link)
164 _tdm_display_destroy_private_output(o);
166 _tdm_display_destroy_caps_pp(&private_display->caps_pp);
167 _tdm_display_destroy_caps_capture(&private_display->caps_capture);
169 private_display->capabilities = 0;
170 private_display->caps_display.max_layer_count = -1;
174 _tdm_display_update_caps_pp(tdm_private_display *private_display, tdm_caps_pp *caps)
176 tdm_func_display *func_display = &private_display->func_display;
178 int bufsize = sizeof(buf);
180 int *len_buf = &bufsize;
184 if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP))
185 return TDM_ERROR_NONE;
187 if (!func_display->display_get_pp_capability)
189 TDM_ERR("no display_get_pp_capability()");
190 return TDM_ERROR_BAD_MODULE;
193 ret = func_display->display_get_pp_capability(private_display->bdata, caps);
194 if (ret != TDM_ERROR_NONE)
196 TDM_ERR("display_get_pp_capability() failed");
197 return TDM_ERROR_BAD_MODULE;
200 TDM_DBG("pp capabilities: %x", caps->capabilities);
202 for (i = 0; i < caps->format_count; i++)
203 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
204 TDM_DBG("pp formats: %s", buf);
205 TDM_DBG("pp min : %dx%d", caps->min_w, caps->min_h);
206 TDM_DBG("pp max : %dx%d", caps->max_w, caps->max_h);
207 TDM_DBG("pp align: %d", caps->preferred_align);
209 return TDM_ERROR_NONE;
213 _tdm_display_update_caps_capture(tdm_private_display *private_display, tdm_caps_capture *caps)
215 tdm_func_display *func_display = &private_display->func_display;
217 int bufsize = sizeof(buf);
219 int *len_buf = &bufsize;
223 if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE))
224 return TDM_ERROR_NONE;
226 if (!func_display->display_get_capture_capability)
228 TDM_ERR("no display_get_capture_capability()");
229 return TDM_ERROR_BAD_MODULE;
232 ret = func_display->display_get_capture_capability(private_display->bdata, caps);
233 if (ret != TDM_ERROR_NONE)
235 TDM_ERR("display_get_capture_capability() failed");
236 return TDM_ERROR_BAD_MODULE;
240 for (i = 0; i < caps->format_count; i++)
241 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
242 TDM_DBG("capture formats: %s", buf);
244 return TDM_ERROR_NONE;
248 _tdm_display_update_caps_layer(tdm_private_display *private_display,
249 tdm_layer *layer_backend, tdm_caps_layer *caps)
251 tdm_func_layer *func_layer = &private_display->func_layer;
253 int bufsize = sizeof(buf);
255 int *len_buf = &bufsize;
259 if (!func_layer->layer_get_capability)
261 TDM_ERR("no layer_get_capability()");
262 return TDM_ERROR_BAD_MODULE;
265 ret = func_layer->layer_get_capability(layer_backend, caps);
266 if (ret != TDM_ERROR_NONE)
268 TDM_ERR("layer_get_capability() failed");
269 return TDM_ERROR_BAD_MODULE;
272 TDM_DBG("layer capabilities: %x", caps->capabilities);
273 TDM_DBG("layer zpos : %d", caps->zpos);
275 for (i = 0; i < caps->format_count; i++)
276 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
277 TDM_DBG("layer formats: %s", buf);
278 for (i = 0; i < caps->prop_count; i++)
279 TDM_DBG("layer props: %d, %s", caps->props[i].id, caps->props[i].name);
281 return TDM_ERROR_NONE;
285 _tdm_display_update_caps_output(tdm_private_display *private_display,
286 tdm_output *output_backend, tdm_caps_output *caps)
288 tdm_func_output *func_output = &private_display->func_output;
292 if (!func_output->output_get_capability)
294 TDM_ERR("no output_get_capability()");
295 return TDM_ERROR_BAD_MODULE;
298 ret = func_output->output_get_capability(output_backend, caps);
299 if (ret != TDM_ERROR_NONE)
301 TDM_ERR("output_get_capability() failed");
302 return TDM_ERROR_BAD_MODULE;
305 TDM_DBG("output maker: %s", caps->maker);
306 TDM_DBG("output model: %s", caps->model);
307 TDM_DBG("output name: %s", caps->name);
308 TDM_DBG("output status: %d", caps->status);
309 TDM_DBG("output type : %d", caps->type);
310 for (i = 0; i < caps->prop_count; i++)
311 TDM_DBG("output props: %d, %s", caps->props[i].id, caps->props[i].name);
312 for (i = 0; i < caps->mode_count; i++)
314 TDM_DBG("output modes: name(%s), clock(%d) vrefresh(%d), flags(%x), type(%d)",
315 caps->modes[i].name, caps->modes[i].clock, caps->modes[i].vrefresh,
316 caps->modes[i].flags, caps->modes[i].type);
317 TDM_DBG("\t\t %d, %d, %d, %d, %d",
318 caps->modes[i].hdisplay, caps->modes[i].hsync_start, caps->modes[i].hsync_end,
319 caps->modes[i].htotal, caps->modes[i].hskew);
320 TDM_DBG("\t\t %d, %d, %d, %d, %d",
321 caps->modes[i].vdisplay, caps->modes[i].vsync_start, caps->modes[i].vsync_end,
322 caps->modes[i].vtotal, caps->modes[i].vscan);
324 TDM_DBG("output min : %dx%d", caps->min_w, caps->min_h);
325 TDM_DBG("output max : %dx%d", caps->max_w, caps->max_h);
326 TDM_DBG("output align: %d", caps->preferred_align);
328 return TDM_ERROR_NONE;
332 _tdm_display_update_layer(tdm_private_display *private_display,
333 tdm_private_output *private_output,
334 tdm_layer *layer_backend)
336 tdm_private_layer *private_layer;
339 private_layer = _tdm_display_find_private_layer(private_output, layer_backend);
342 private_layer = calloc(1, sizeof(tdm_private_layer));
343 TDM_RETURN_VAL_IF_FAIL(private_layer != NULL, TDM_ERROR_OUT_OF_MEMORY);
345 LIST_ADD(&private_layer->link, &private_output->layer_list);
346 private_layer->private_display = private_display;
347 private_layer->private_output = private_output;
348 private_layer->layer_backend = layer_backend;
350 LIST_INITHEAD(&private_layer->capture_list);
352 private_layer->usable = 1;
355 _tdm_display_destroy_caps_layer(&private_layer->caps);
357 ret = _tdm_display_update_caps_layer(private_display, layer_backend, &private_layer->caps);
358 if (ret != TDM_ERROR_NONE)
361 return TDM_ERROR_NONE;
363 _tdm_display_destroy_private_layer(private_layer);
368 _tdm_display_update_output(tdm_private_display *private_display,
369 tdm_output *output_backend, int pipe)
371 tdm_func_output *func_output = &private_display->func_output;
372 tdm_private_output *private_output = NULL;
373 tdm_layer **layers = NULL;
374 int layer_count = 0, i;
377 private_output = _tdm_display_find_private_output(private_display, output_backend);
380 private_output = calloc(1, sizeof(tdm_private_output));
381 TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OUT_OF_MEMORY);
383 LIST_ADD(&private_output->link, &private_display->output_list);
384 private_output->private_display = private_display;
385 private_output->output_backend = output_backend;
386 private_output->pipe = pipe;
388 LIST_INITHEAD(&private_output->layer_list);
389 LIST_INITHEAD(&private_output->capture_list);
390 LIST_INITHEAD(&private_output->vblank_handler_list);
391 LIST_INITHEAD(&private_output->commit_handler_list);
394 _tdm_display_destroy_caps_output(&private_output->caps);
396 ret = _tdm_display_update_caps_output(private_display, output_backend, &private_output->caps);
397 if (ret != TDM_ERROR_NONE)
400 layers = func_output->output_get_layers(output_backend, &layer_count, &ret);
401 if (ret != TDM_ERROR_NONE)
404 for (i = 0; i < layer_count; i++)
406 ret = _tdm_display_update_layer(private_display, private_output, layers[i]);
407 if (ret != TDM_ERROR_NONE)
413 return TDM_ERROR_NONE;
415 _tdm_display_destroy_private_output(private_output);
421 _tdm_display_update_internal(tdm_private_display *private_display, int only_display)
423 tdm_func_display *func_display = &private_display->func_display;
424 tdm_output **outputs = NULL;
425 int output_count = 0, i;
428 LIST_INITHEAD(&private_display->output_list);
429 LIST_INITHEAD(&private_display->pp_list);
433 ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
434 if (ret != TDM_ERROR_NONE)
437 ret = _tdm_display_update_caps_capture(private_display, &private_display->caps_capture);
438 if (ret != TDM_ERROR_NONE)
442 outputs = func_display->display_get_outputs(private_display->bdata, &output_count, &ret);
443 if (ret != TDM_ERROR_NONE)
446 for (i = 0; i < output_count; i++)
448 ret = _tdm_display_update_output(private_display, outputs[i], i);
449 if (ret != TDM_ERROR_NONE)
455 return TDM_ERROR_NONE;
458 _tdm_display_destroy_private_display(private_display);
465 tdm_display_update(tdm_display *dpy)
467 tdm_private_display *private_display;
470 TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
472 private_display = dpy;
473 pthread_mutex_lock(&private_display->lock);
475 ret = _tdm_display_update_internal(private_display, 1);
477 pthread_mutex_unlock(&private_display->lock);
482 #define SUFFIX_MODULE ".so"
483 #define DEFAULT_MODULE "libtdm-default"SUFFIX_MODULE
487 static tdm_private_display *g_private_display;
488 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
491 _tdm_display_check_module(tdm_backend_module *module)
498 abimaj = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_VERSION);
499 abimin = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_VERSION);
501 TDM_INFO("TDM module ABI version : %d.%d", abimaj, abimin);
503 name = module->name ? module->name : "unknown";
504 vendor = module->vendor ? module->vendor : "unknown";
505 major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
506 minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
508 TDM_INFO("TDM module name: %s", name);
509 TDM_INFO("'%s' vendor: %s", name, vendor);
510 TDM_INFO("'%s' version: %d.%d", name, major, minor);
514 TDM_ERR("'%s' major version mismatch, %d != %d", name, major, abimaj);
515 return TDM_ERROR_BAD_MODULE;
520 TDM_ERR("'%s' minor version(%d) is newer than %d", name, minor, abimin);
521 return TDM_ERROR_BAD_MODULE;
526 TDM_ERR("'%s' doesn't have init function", name);
527 return TDM_ERROR_BAD_MODULE;
532 TDM_ERR("'%s' doesn't have deinit function", name);
533 return TDM_ERROR_BAD_MODULE;
536 return TDM_ERROR_NONE;
540 _tdm_display_check_backend_functions(tdm_private_display *private_display)
542 tdm_func_display *func_display = &private_display->func_display;
543 tdm_func_output *func_output = &private_display->func_output;
544 tdm_func_layer *func_layer = &private_display->func_layer;
547 /* below functions should be implemented in backend side */
549 TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
550 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy, TDM_ERROR_BAD_MODULE);
551 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
552 TDM_RETURN_VAL_IF_FAIL(func_output->output_get_capability, TDM_ERROR_BAD_MODULE);
553 TDM_RETURN_VAL_IF_FAIL(func_output->output_get_layers, TDM_ERROR_BAD_MODULE);
554 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_get_capability, TDM_ERROR_BAD_MODULE);
556 ret = func_display->display_get_capabilitiy(private_display->bdata,
557 &private_display->caps_display);
558 if (ret != TDM_ERROR_NONE)
560 TDM_ERR("display_get_capabilitiy() failed");
561 return TDM_ERROR_BAD_MODULE;
564 if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP)
566 tdm_func_pp *func_pp = &private_display->func_pp;
567 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability, TDM_ERROR_BAD_MODULE);
568 TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
569 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
570 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
571 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
574 if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)
576 tdm_func_capture *func_capture = &private_display->func_capture;
577 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability, TDM_ERROR_BAD_MODULE);
578 TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture, TDM_ERROR_BAD_MODULE);
579 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE);
580 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
581 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
582 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler, TDM_ERROR_BAD_MODULE);
585 return TDM_ERROR_NONE;
589 _tdm_display_load_module_with_file(tdm_private_display *private_display, const char *file)
591 char path[PATH_MAX] = {0,};
592 tdm_backend_module *module_data;
596 snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
598 module = dlopen(path, RTLD_LAZY);
601 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
602 return TDM_ERROR_BAD_MODULE;
605 module_data = dlsym(module, "tdm_backend_module_data");
608 TDM_ERR("'%s' doesn't have data object", file);
609 ret = TDM_ERROR_BAD_MODULE;
613 /* check if version, init() and deinit() are valid or not */
614 ret = _tdm_display_check_module(module_data);
615 if (ret != TDM_ERROR_NONE)
618 /* We don't care if backend_data is NULL or not. It's up to backend. */
619 private_display->bdata = module_data->init((tdm_display*)private_display, &ret);
620 if (ret != TDM_ERROR_NONE)
622 TDM_ERR("'%s' init failed", file);
626 ret = _tdm_display_check_backend_functions(private_display);
627 if (ret != TDM_ERROR_NONE)
629 module_data->deinit(private_display->bdata);
630 private_display->bdata = NULL;
634 private_display->module_data = module_data;
635 private_display->module = module;
637 TDM_INFO("Success to load module(%s)", file);
639 return TDM_ERROR_NONE;
646 _tdm_display_load_module(tdm_private_display *private_display)
648 const char *module_name;
649 struct dirent **namelist;
653 module_name = getenv("TDM_MODULE");
655 module_name = DEFAULT_MODULE;
657 /* load bufmgr priv from default lib */
658 ret = _tdm_display_load_module_with_file(private_display, module_name);
659 if (ret == TDM_ERROR_NONE)
660 return TDM_ERROR_NONE;
662 /* load bufmgr priv from configured path */
663 n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
666 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
667 return TDM_ERROR_BAD_MODULE;
670 ret = TDM_ERROR_BAD_MODULE;
673 if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
674 ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
684 _tdm_display_unload_module(tdm_private_display *private_display)
686 if (private_display->module_data)
687 private_display->module_data->deinit(private_display->bdata);
688 if (private_display->module)
689 dlclose(private_display->module);
691 private_display->bdata = NULL;
692 private_display->module_data = NULL;
693 private_display->module = NULL;
697 tdm_display_init(tdm_error *error)
699 tdm_private_display *private_display = NULL;
703 pthread_mutex_lock(&gLock);
705 if (g_private_display)
707 g_private_display->init_count++;
708 pthread_mutex_unlock(&gLock);
710 *error = TDM_ERROR_NONE;
711 return g_private_display;
714 debug = getenv("TDM_DEBUG");
715 if (debug && (strstr(debug, "1")))
718 private_display = calloc(1, sizeof(tdm_private_display));
719 if (!private_display)
721 ret = TDM_ERROR_OUT_OF_MEMORY;
722 TDM_ERR("'private_display != NULL' failed");
726 if (pthread_mutex_init(&private_display->lock, NULL))
728 ret = TDM_ERROR_OPERATION_FAILED;
729 TDM_ERR("mutex init failed: %m");
730 goto failed_mutex_init;
733 ret = _tdm_display_load_module(private_display);
734 if (ret != TDM_ERROR_NONE)
737 ret = _tdm_display_update_internal(private_display, 0);
738 if (ret != TDM_ERROR_NONE)
741 private_display->init_count = 1;
743 g_private_display = private_display;
746 *error = TDM_ERROR_NONE;
748 pthread_mutex_unlock(&gLock);
750 return (tdm_display*)private_display;
753 _tdm_display_unload_module(private_display);
755 pthread_mutex_destroy(&private_display->lock);
757 free(private_display);
762 pthread_mutex_unlock(&gLock);
767 tdm_display_deinit(tdm_display *dpy)
769 tdm_private_display *private_display = dpy;
771 if (!private_display)
774 pthread_mutex_lock(&gLock);
776 private_display->init_count--;
777 if (private_display->init_count > 0)
779 pthread_mutex_unlock(&gLock);
783 pthread_mutex_lock(&private_display->lock);
785 _tdm_display_destroy_private_display(private_display);
786 _tdm_display_unload_module(private_display);
788 pthread_mutex_unlock(&private_display->lock);
790 pthread_mutex_destroy(&private_display->lock);
791 free(private_display);
794 pthread_mutex_unlock(&gLock);