wscript 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. #! /usr/bin/env python
  2. # The following example shows how several build processes can collaborate
  3. # to stop spawning new processes when a special task of type K is executed
  4. # this may be useful for link tasks for example
  5. def options(opt):
  6. opt.add_option('--loops', action='store', type='int', default=5, help='amount of cpu-intensive loops to perform')
  7. def configure(conf):
  8. busy = conf.path.find_node('look_busy.py').abspath()
  9. conf.env.NOT_BUSY = ('%s 0' % busy).split()
  10. conf.env.VERY_BUSY = ('%s %d' % (busy, conf.options.loops)).split()
  11. def build(bld):
  12. bld.link_limit = 1
  13. bld.lockfile = bld.path.parent.make_node('busy_lock.txt').abspath()
  14. for i in range(2):
  15. for k in range(5):
  16. bld(rule='${NOT_BUSY}', always=True)
  17. bld(rule='${VERY_BUSY}', always=True, exclusive=True)
  18. for k in range(10):
  19. bld(rule='${NOT_BUSY}', always=True)
  20. import os, fcntl, threading, errno, time
  21. from waflib import Task
  22. lock = threading.Lock()
  23. def lock_maxjob(self):
  24. # lock the file, telling other build processes to avoid spawining tasks during that time
  25. while True:
  26. try:
  27. self.lockfd = os.open(self.generator.bld.lockfile, os.O_TRUNC | os.O_CREAT | os.O_RDWR)
  28. fcntl.flock(self.lockfd, fcntl.LOCK_EX | fcntl.LOCK_NB)
  29. except EnvironmentError as e:
  30. if e.errno in (errno.EACCES, errno.EAGAIN):
  31. time.sleep(0.3)
  32. continue
  33. raise
  34. os.write(self.lockfd, "%d" % os.getpid())
  35. self.start_time = time.time()
  36. break
  37. def release_maxjob(self):
  38. # release the lock file
  39. print("> long task %d" % (time.time() - self.start_time))
  40. try:
  41. os.remove(self.generator.bld.lockfile)
  42. os.close(self.lockfd)
  43. except OSError, e:
  44. # of someone else has removed the lock... bad luck! but do not fail here
  45. print "unexpected failure", e
  46. pass
  47. def wait_maxjob(self):
  48. # wait on the lock file.. up to a certain limit
  49. while True:
  50. try:
  51. ini = os.stat(self.generator.bld.lockfile).st_mtime
  52. except OSError, e:
  53. return
  54. diff = time.time() - ini
  55. if diff > 300: # stale lock file? wait 5 minutes
  56. return
  57. time.sleep(0.5)
  58. # the method process is called by threads...
  59. def process2(self):
  60. if getattr(self.generator, 'exclusive', False):
  61. lock.acquire()
  62. try:
  63. self.lock_maxjob()
  64. finally:
  65. lock.release()
  66. else:
  67. self.wait_maxjob()
  68. ret = self.process_bound_maxjobs()
  69. if getattr(self.generator, 'exclusive', False):
  70. lock.acquire()
  71. try:
  72. self.release_maxjob()
  73. finally:
  74. lock.release()
  75. return ret
  76. def process(self):
  77. try:
  78. process2(self)
  79. except Exception, e:
  80. print type(e), e
  81. Task.Task.process_bound_maxjobs = Task.Task.process
  82. Task.Task.process = process
  83. Task.Task.lock_maxjob = lock_maxjob
  84. Task.Task.release_maxjob = release_maxjob
  85. Task.Task.wait_maxjob = wait_maxjob